From 6e5b92305944f2bdad71972750ef756660705e63 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Mon, 28 Apr 2025 03:53:14 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86=E6=9B=B4=E5=A4=9A?= =?UTF-8?q?=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../skript/event/EvtCustomClick.java | 1 + .../src/main/resources/translations/en.yml | 35 ++++- .../bukkit/block/BukkitBlockManager.java | 84 ++++++------ .../bukkit/block/BukkitCustomBlock.java | 28 +++- .../behavior/ConcretePowderBlockBehavior.java | 3 +- .../block/behavior/CropBlockBehavior.java | 3 +- .../block/behavior/LeavesBlockBehavior.java | 5 +- .../block/behavior/SaplingBlockBehavior.java | 5 +- .../behavior/StrippableBlockBehavior.java | 3 +- .../behavior/SugarCaneBlockBehavior.java | 3 +- .../bukkit/item/BukkitItemManager.java | 20 ++- .../item/behavior/BlockItemBehavior.java | 3 +- .../item/behavior/FurnitureItemBehavior.java | 3 +- .../LiquidCollisionBlockItemBehavior.java | 3 +- .../bukkit/loot/BukkitVanillaLootManager.java | 11 +- .../craftengine/core/block/BlockSettings.java | 3 +- .../craftengine/core/block/CustomBlock.java | 80 +++++++++++- .../core/block/behavior/BlockBehaviors.java | 3 +- .../core/font/AbstractFontManager.java | 120 +++++++++--------- .../core/item/behavior/ItemBehaviors.java | 9 +- .../item/recipe/AbstractRecipeManager.java | 5 +- .../core/loot/number/NumberProviders.java | 5 +- .../core/pack/model/BaseItemModel.java | 11 +- .../core/pack/model/CompositeItemModel.java | 26 ++-- .../core/pack/model/ConditionItemModel.java | 19 ++- .../core/pack/model/ItemModels.java | 3 +- .../pack/model/RangeDispatchItemModel.java | 28 ++-- .../core/pack/model/SelectItemModel.java | 49 ++++--- .../model/generation/ModelGeneration.java | 26 ++-- .../plugin/locale/TranslationManagerImpl.java | 3 +- .../core/sound/AbstractSoundManager.java | 11 +- 31 files changed, 396 insertions(+), 215 deletions(-) diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomClick.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomClick.java index 68bcdb48b..8c37c2a04 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomClick.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/skript/event/EvtCustomClick.java @@ -22,6 +22,7 @@ public class EvtCustomClick extends SkriptEvent { private final static int RIGHT = 1, LEFT = 2, ANY = RIGHT | LEFT; public final static ClickEventTracker interactTracker = new ClickEventTracker(Skript.getInstance()); + @SuppressWarnings("unchecked") public static void register() { Skript.registerEvent("Interact Custom Block Furniture", EvtCustomClick.class, new Class[]{CustomBlockInteractEvent.class, FurnitureInteractEvent.class}, "[(" + RIGHT + ":right|" + LEFT + ":left)(| |-)][mouse(| |-)]click[ing] [on %-unsafeblockstatematchers/strings%] [(with|using|holding) %-itemtype%]", diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index 7937c5b2b..546101339 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -67,7 +67,7 @@ warning.config.not_a_section: "Issue found in file - '.Issue found in file - Duplicated image ''." warning.config.image.lack_height: "Issue found in file - The image '' is missing the required 'height' argument." warning.config.image.height_smaller_than_ascent: "Issue found in file - The image '' violates the bitmap image rule: 'height' should be no lower than 'ascent'." -warning.config.image.no_file: "Issue found in file - The image '' is missing the required 'file' argument." +warning.config.image.lack_file: "Issue found in file - The image '' is missing the required 'file' argument." warning.config.image.invalid_resource_location: "Issue found in file - The image '' has a 'file' argument [] that contains legal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters" warning.config.image.invalid_font_name: "Issue found in file - The image '' has a 'font' argument [] that contains legal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters" warning.config.image.lack_char: "Issue found in file - The image '' is missing the required 'char' argument." @@ -81,6 +81,7 @@ warning.config.vanilla_loot.type_not_exist: "Issue found in file warning.config.vanilla_loot.block.invalid_target: "Issue found in file - Invalid block target [] in vanilla loot ''." warning.config.sound.duplicated: "Issue found in file - Duplicated sound ''." warning.config.jukebox_song.duplicated: "Issue found in file - Duplicated jukebox song ''." +warning.config.jukebox_song.lack_sound: "Issue found in file - The jukebox song '' is missing the required 'sound' argument." warning.config.furniture.duplicated: "Issue found in file - Duplicated furniture ''." warning.config.furniture.lack_placement: "Issue found in file - The furniture '' is missing the required 'placement' argument." warning.config.furniture.element.lack_item: "Issue found in file - The furniture '' is missing the required 'item' argument for one of its elements." @@ -93,6 +94,22 @@ warning.config.item.invalid_material: "Issue found in file - The warning.config.item.bad_custom_model_data_value: "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.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.lack_model_id: "Issue found in file - The item '' is missing the required 'custom-model-data' or 'item-model' argument." +warning.config.item.behavior.lack_type: "Issue found in file - The item '' is missing the required 'type' argument for its item behavior." +warning.config.item.behavior.invalid_type: "Issue found in file - The item '' is using an invalid item behavior type ''." +warning.config.item.behavior.block.lack_block: "Issue found in file - The item '' is missing the required 'block' argument for 'block_item' behavior." +warning.config.item.behavior.furniture.lack_furniture: "Issue found in file - The item '' is missing the required 'furniture' argument for 'furniture_item' behavior." +warning.config.item.behavior.liquid_collision_block.lack_block: "Issue found in file - The item '' is missing the required 'block' argument for 'liquid_collision_block_item' behavior." +warning.config.item.model.invalid_type: "Issue found in file - The item '' is using an invalid model type ''." +warning.config.item.model.base.lack_path: "Issue found in file - The item '' is missing the required 'path' argument for 'minecraft:model'." +warning.config.item.model.base.invalid_resource_location: "Issue found in file - The item '' has an invalid 'path' argument [] for 'minecraft:model' which contains legal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters." +warning.config.item.model.condition.lack_on_true: "Issue found in file - The item '' is missing the required 'on-true' argument for 'minecraft:condition'." +warning.config.item.model.condition.lack_on_false: "Issue found in file - The item '' is missing the required 'on-false' argument for 'minecraft:condition'." +warning.config.item.model.composite.lack_models: "Issue found in file - The item '' is missing the required 'models' argument for 'minecraft:composite'." +warning.config.item.model.range_dispatch.lack_entries: "Issue found in file - The item '' is missing the required 'entries' argument for 'minecraft:composite'." +warning.config.item.model.range_dispatch.entry.lack_model: "Issue found in file - The item '' is missing the required 'model' argument for one of the entries in 'minecraft:composite'." +warning.config.item.model.select.lack_cases: "Issue found in file - The item '' is missing the required 'cases' argument for 'minecraft:select'." +warning.config.item.model.select.case.lack_when: "Issue found in file - The item '' is missing the required 'when' argument for one of the cases in 'minecraft:select'." +warning.config.item.model.select.case.lack_model: "Issue found in file - The item '' is missing the required 'model' argument for one of the cases in 'minecraft:select'." warning.config.block.duplicated: "Issue found in file - Duplicated block ''." warning.config.block.lack_state: "Issue found in file - The block '' is missing the required 'state' argument." warning.config.block.state.lack_real_id: "Issue found in file - The block '' is missing the required 'id' argument for 'state'." @@ -113,6 +130,18 @@ warning.config.block.state.no_model_set: "Issue found in file - warning.config.block.state.invalid_real_state_id: "Issue found in file - The block '' is using a real block state '' that exceeds the available slot range '0~'. Consider adding more real states in 'additional-real-blocks.yml' if the slots are used up." warning.config.block.state.model.lack_path: "Issue found in file - The block '' is missing the required 'path' option for 'model'." warning.config.block.state.model.invalid_resource_location: "Issue found in file - The block '' has a 'path' argument [] that contains legal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters" +warning.config.block.settings.unknown: "Issue found in file - The block '' is using an unknown setting type ''." +warning.config.block.behavior.lack_type: "Issue found in file - The block '' is missing the required 'type' argument for its block behavior." +warning.config.block.behavior.invalid_type: "Issue found in file - The block '' is using an invalid block behavior type ''." +warning.config.block.behavior.concrete.lack_solid_block: "Issue found in file - The block '' is missing the required 'solid-block' option for 'concrete_block' behavior." +warning.config.block.behavior.crop.lack_age: "Issue found in file - The block '' is missing the required 'age' property for 'crop_block' behavior." +warning.config.block.behavior.sugar_cane.lack_age: "Issue found in file - The block '' is missing the required 'age' property for 'sugar_cane_block' behavior." +warning.config.block.behavior.leaves.lack_persistent: "Issue found in file - The block '' is missing the required 'persistent' property for 'leaves_block' behavior." +warning.config.block.behavior.leaves.lack_distance: "Issue found in file - The block '' is missing the required 'distance' property for 'leaves_block' behavior." +warning.config.block.behavior.sapling.lack_stage: "Issue found in file - The block '' is missing the required 'stage' property for 'sapling_block' behavior." +warning.config.block.behavior.sapling.lack_feature: "Issue found in file - The block '' is missing the required 'feature' argument for 'sapling_block' behavior." +warning.config.block.behavior.strippable.lack_stripped: "Issue found in file - The block '' is missing the required 'stripped' argument for 'strippable_block' behavior." +warning.config.model.generation.lack_parent: "Issue found in file - The config '' is missing the required 'parent' argument in 'generation' section." warning.config.model.generation.conflict: "Issue found in file - Failed to generate model for '' as two or more configurations attempt to generate different json models with the same path: ''" warning.config.model.generation.texture.invalid_resource_location: "Issue found in file - The config '' has a '' texture argument [] that contains legal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters" warning.config.model.generation.parent.invalid_resource_location: "Issue found in file - The config '' has a parent argument [] that contains legal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters" @@ -162,4 +191,6 @@ warning.config.loot_table.entry.invalid_type: "Issue found in file Issue found in file - '' has a misconfigured loot table, entry 'exp' is missing the required argument 'count'." warning.config.loot_table.entry.item.lack_item: "Issue found in file - '' has a misconfigured loot table, entry 'item' is missing the required argument 'item'." warning.config.loot_table.condition.lack_type: "Issue found in file - '' has a misconfigured loot table, one of the conditions is missing the required argument 'type'." -warning.config.loot_table.condition.invalid_type: "Issue found in file - '' has a misconfigured loot table, one of the conditions is using an invalid condition type ''." \ No newline at end of file +warning.config.loot_table.condition.invalid_type: "Issue found in file - '' has a misconfigured loot table, one of the conditions is using an invalid condition type ''." +warning.config.loot_table.number.lack_type: "Issue found in file - '' has a misconfigured loot table, one of the numbers is missing the required argument 'type'." +warning.config.loot_table.number.invalid_type: "Issue found in file - '' has a misconfigured loot table, one of the numbers is using an invalid number type ''." \ No newline at end of file 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 42f8e9c4d..4660f3744 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 @@ -26,6 +26,7 @@ import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; @@ -331,13 +332,28 @@ public class BukkitBlockManager extends AbstractBlockManager { public void parseSection(Pack pack, Path path, Key id, Map section) { // check duplicated config if (byId.containsKey(id)) { - TranslationManager.instance().log("warning.config.block.duplicated", path.toString(), id.toString()); - return; + throw new LocalizedResourceConfigException("warning.config.block.duplicated", path, id); } // read block settings - BlockSettings settings = BlockSettings.fromMap(MiscUtils.castToMap(section.getOrDefault("settings", Map.of()), false)); + BlockSettings settings; + try { + settings = BlockSettings.fromMap(MiscUtils.castToMap(section.getOrDefault("settings", Map.of()), false)); + } catch (LocalizedResourceConfigException e) { + e.setPath(path); + e.setId(id); + throw e; + } + // read loot table - LootTable lootTable = LootTable.fromMap(MiscUtils.castToMap(section.getOrDefault("loot", Map.of()), false)); + LootTable lootTable; + try { + lootTable = LootTable.fromMap(MiscUtils.castToMap(section.getOrDefault("loot", Map.of()), false)); + } catch (LocalizedResourceConfigException e) { + e.setPath(path); + e.setId(id); + throw e; + } + // read states Map> properties; Map appearances; @@ -347,8 +363,7 @@ public class BukkitBlockManager extends AbstractBlockManager { properties = Map.of(); int internalId = MiscUtils.getAsInt(stateSection.getOrDefault("id", -1)); if (internalId < 0) { - TranslationManager.instance().log("warning.config.block.state.lack_real_id", path.toString(), id.toString()); - return; + throw new LocalizedResourceConfigException("warning.config.block.state.lack_real_id", path, id); } Pair pair = parseAppearanceSection(pack, path, id, stateSection); @@ -358,34 +373,27 @@ public class BukkitBlockManager extends AbstractBlockManager { Key internalBlockId = Key.of(CraftEngine.NAMESPACE, pair.left().value() + "_" + internalId); int internalBlockRegistryId = MiscUtils.getAsInt(internalId2StateId.getOrDefault(internalBlockId, -1)); if (internalBlockRegistryId == -1) { - TranslationManager.instance().log("warning.config.block.state.invalid_real_state_id", - path.toString(), - id.toString(), + throw new LocalizedResourceConfigException("warning.config.block.state.invalid_real_state_id", path, id, pair.left().value() + "_" + internalId, - String.valueOf(MiscUtils.getAsInt(registeredRealBlockSlots.get(pair.left()))-1) - ); - return; + String.valueOf(MiscUtils.getAsInt(registeredRealBlockSlots.get(pair.left()))-1)); } variants = Map.of("", new VariantState("default", settings, internalBlockRegistryId)); } else { // states Map statesSection = MiscUtils.castToMap(section.get("states"), true); if (statesSection == null) { - TranslationManager.instance().log("warning.config.block.lack_state", path.toString(), id.toString()); - return; + throw new LocalizedResourceConfigException("warning.config.block.lack_state", path, id); } // properties Map propertySection = MiscUtils.castToMap(statesSection.get("properties"), true); if (propertySection == null) { - TranslationManager.instance().log("warning.config.block.state.lack_properties", path.toString(), id.toString()); - return; + throw new LocalizedResourceConfigException("warning.config.block.state.lack_properties", path, id); } properties = parseProperties(path, id, propertySection); // appearance Map appearancesSection = MiscUtils.castToMap(statesSection.get("appearances"), true); if (appearancesSection == null) { - TranslationManager.instance().log("warning.config.block.state.lack_appearances", path.toString(), id.toString()); - return; + throw new LocalizedResourceConfigException("warning.config.block.state.lack_appearances", path, id); } appearances = new HashMap<>(); Map tempTypeMap = new HashMap<>(); @@ -400,8 +408,7 @@ public class BukkitBlockManager extends AbstractBlockManager { // variants Map variantsSection = MiscUtils.castToMap(statesSection.get("variants"), true); if (variantsSection == null) { - TranslationManager.instance().log("warning.config.block.state.lack_variants", path.toString(), id.toString()); - return; + throw new LocalizedResourceConfigException("warning.config.block.state.lack_variants", path, id); } variants = new HashMap<>(); for (Map.Entry variantEntry : variantsSection.entrySet()) { @@ -410,25 +417,19 @@ public class BukkitBlockManager extends AbstractBlockManager { String variantName = variantEntry.getKey(); String appearance = (String) variantSection.get("appearance"); if (appearance == null) { - TranslationManager.instance().log("warning.config.block.state.variant.lack_appearance", path.toString(), id.toString(), variantName); - return; + throw new LocalizedResourceConfigException("warning.config.block.state.variant.lack_appearance", path, id, variantName); } if (!appearances.containsKey(appearance)) { - TranslationManager.instance().log("warning.config.block.state.variant.invalid_appearance", path.toString(), id.toString(), variantName, appearance); - return; + throw new LocalizedResourceConfigException("warning.config.block.state.variant.invalid_appearance", path, id, variantName, appearance); } int internalId = MiscUtils.getAsInt(variantSection.getOrDefault("id", -1)); Key baseBlock = tempTypeMap.get(appearance); Key internalBlockId = Key.of(CraftEngine.NAMESPACE, baseBlock.value() + "_" + internalId); int internalBlockRegistryId = MiscUtils.getAsInt(internalId2StateId.getOrDefault(internalBlockId, -1)); if (internalBlockRegistryId == -1) { - TranslationManager.instance().log("warning.config.block.state.invalid_real_state_id", - path.toString(), - id.toString(), + throw new LocalizedResourceConfigException("warning.config.block.state.invalid_real_state_id", path, id, internalBlockId.toString(), - String.valueOf(MiscUtils.getAsInt(registeredRealBlockSlots.getOrDefault(baseBlock, 1)) - 1) - ); - return; + String.valueOf(MiscUtils.getAsInt(registeredRealBlockSlots.getOrDefault(baseBlock, 1)) - 1)); } Map anotherSetting = MiscUtils.castToMap(variantSection.get("settings"), true); variants.put(variantName, new VariantState(appearance, anotherSetting == null ? settings : BlockSettings.ofFullCopy(settings, anotherSetting), internalBlockRegistryId)); @@ -436,12 +437,23 @@ public class BukkitBlockManager extends AbstractBlockManager { } } - // create or get block holder - Holder.Reference holder = BuiltInRegistries.BLOCK.get(id).orElseGet(() -> - ((WritableRegistry) BuiltInRegistries.BLOCK).registerForHolder(new ResourceKey<>(BuiltInRegistries.BLOCK.key().location(), id))); - // create block - Map behaviorSection = MiscUtils.castToMap(section.getOrDefault("behavior", Map.of()), false); - BukkitCustomBlock block = new BukkitCustomBlock(id, holder, properties, appearances, variants, settings, behaviorSection, lootTable); + Map behaviors = MiscUtils.castToMap(section.getOrDefault("behavior", Map.of()), false); + + CustomBlock block; + try { + block = BukkitCustomBlock.builder(id) + .appearances(appearances) + .variantMapper(variants) + .lootTable(lootTable) + .properties(properties) + .settings(settings) + .behavior(behaviors) + .build(); + } catch (LocalizedResourceConfigException e) { + e.setPath(path); + e.setId(id); + throw e; + } // bind appearance and real state for (ImmutableBlockState state : block.variantProvider().states()) { 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 2bb530a75..209e34662 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 @@ -9,8 +9,11 @@ import net.momirealms.craftengine.core.block.*; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.plugin.CraftEngine; +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 net.momirealms.craftengine.core.util.Tristate; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.shared.ObjectHolder; @@ -25,17 +28,17 @@ import java.util.Set; public class BukkitCustomBlock extends CustomBlock { - public BukkitCustomBlock( + protected BukkitCustomBlock( Key id, Holder.Reference holder, Map> properties, Map appearances, Map variantMapper, BlockSettings settings, - Map behaviorSettings, + Map behavior, @Nullable LootTable lootTable ) { - super(id, holder, properties, appearances, variantMapper, settings, behaviorSettings, lootTable); + super(id, holder, properties, appearances, variantMapper, settings, behavior, lootTable); } @SuppressWarnings("unchecked") @@ -139,4 +142,23 @@ public class BukkitCustomBlock extends CustomBlock { CraftEngine.instance().logger().warn("Failed to init block settings", e); } } + + public static Builder builder(Key id) { + return new Builder(id); + } + + public static class Builder extends CustomBlock.Builder { + + protected Builder(Key id) { + super(id); + } + + @Override + public CustomBlock build() { + // create or get block holder + Holder.Reference holder = BuiltInRegistries.BLOCK.get(id).orElseGet(() -> + ((WritableRegistry) BuiltInRegistries.BLOCK).registerForHolder(new ResourceKey<>(BuiltInRegistries.BLOCK.key().location(), id))); + return new BukkitCustomBlock(id, holder, properties, appearances, variantMapper, settings, behavior, lootTable); + } + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ConcretePowderBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ConcretePowderBlockBehavior.java index 6f8cd8f8b..0ab2e2870 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ConcretePowderBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ConcretePowderBlockBehavior.java @@ -13,6 +13,7 @@ import net.momirealms.craftengine.core.block.UpdateOption; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; @@ -159,7 +160,7 @@ public class ConcretePowderBlockBehavior extends FallingBlockBehavior { int hurtMax = MiscUtils.getAsInt(arguments.getOrDefault("max-hurt", -1)); String solidBlock = (String) arguments.get("solid-block"); if (solidBlock == null) { - throw new IllegalArgumentException("No `solid-block` specified for concrete powder block behavior"); + throw new LocalizedResourceConfigException("warning.config.block.behavior.concrete.lack_solid_block", new NullPointerException("No `solid-block` specified for concrete powder block behavior")); } return new ConcretePowderBlockBehavior(block, hurtAmount, hurtMax, Key.of(solidBlock)); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java index 1141f6815..ddf2a9bae 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java @@ -16,6 +16,7 @@ import net.momirealms.craftengine.core.loot.LootContext; import net.momirealms.craftengine.core.loot.number.NumberProvider; import net.momirealms.craftengine.core.loot.number.NumberProviders; import net.momirealms.craftengine.core.loot.parameter.LootParameters; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.RandomUtils; import net.momirealms.craftengine.core.util.Tuple; @@ -170,7 +171,7 @@ public class CropBlockBehavior extends BushBlockBehavior { Tuple, Set, Set> tuple = readTagsAndState(arguments, false); Property ageProperty = (Property) block.getProperty("age"); if (ageProperty == null) { - throw new IllegalArgumentException("age property not set for crop"); + throw new LocalizedResourceConfigException("warning.config.block.behavior.crop.lack_age", new IllegalArgumentException("age property not set for crop")); } int minGrowLight = MiscUtils.getAsInt(arguments.getOrDefault("light-requirement", 9)); float growSpeed = MiscUtils.getAsFloat(arguments.getOrDefault("grow-speed", 0.125f)); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LeavesBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LeavesBlockBehavior.java index 9982700fa..dd12c44ec 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LeavesBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LeavesBlockBehavior.java @@ -14,6 +14,7 @@ import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.loot.parameter.LootParameters; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; @@ -174,11 +175,11 @@ public class LeavesBlockBehavior extends WaterLoggedBlockBehavior { public BlockBehavior create(CustomBlock block, Map arguments) { Property persistent = (Property) block.getProperty("persistent"); if (persistent == null) { - throw new NullPointerException("persistent property not set for block " + block.id()); + throw new LocalizedResourceConfigException("warning.config.block.behavior.leaves.lack_persistent", new NullPointerException("persistent property not set for block " + block.id())); } Property distance = (Property) block.getProperty("distance"); if (distance == null) { - throw new NullPointerException("distance not set for block " + block.id()); + throw new LocalizedResourceConfigException("warning.config.block.behavior.leaves.lack_distance", new NullPointerException("distance property not set for block " + block.id())); } Property waterlogged = (Property) block.getProperty("waterlogged"); int actual = distance.possibleValues().get(distance.possibleValues().size() - 1); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java index 666114c6e..8f5c7489e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java @@ -10,6 +10,7 @@ import net.momirealms.craftengine.core.block.UpdateOption; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.RandomUtils; @@ -142,11 +143,11 @@ public class SaplingBlockBehavior extends BushBlockBehavior { public BlockBehavior create(CustomBlock block, Map arguments) { String feature = (String) arguments.get("feature"); if (feature == null) { - throw new IllegalArgumentException("feature is null"); + throw new LocalizedResourceConfigException("warning.config.block.behavior.sapling.lack_feature", new IllegalArgumentException("'feature' is required for sapling block behavior")); } Property stageProperty = (Property) block.getProperty("stage"); if (stageProperty == null) { - throw new IllegalArgumentException("stage property not set for sapling"); + throw new LocalizedResourceConfigException("warning.config.block.behavior.sapling.lack_stage", new IllegalArgumentException("stage property not set for sapling")); } double boneMealSuccessChance = MiscUtils.getAsDouble(arguments.getOrDefault("bone-meal-success-chance", 0.45)); Tuple, Set, Set> tuple = readTagsAndState(arguments, false); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StrippableBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StrippableBlockBehavior.java index 6a5d4ee7f..785050033 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StrippableBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StrippableBlockBehavior.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.block.behavior; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.shared.block.BlockBehavior; @@ -26,7 +27,7 @@ public class StrippableBlockBehavior extends BukkitBlockBehavior { public BlockBehavior create(CustomBlock block, Map arguments) { String stripped = (String) arguments.get("stripped"); if (stripped == null) { - throw new IllegalArgumentException("stripped is null"); + throw new LocalizedResourceConfigException("warning.config.block.behavior.strippable.lack_stripped", new IllegalArgumentException("'stripped' is required for strippable block behavior")); } return new StrippableBlockBehavior(block, Key.of(stripped)); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java index 4a504d371..2848f97de 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java @@ -14,6 +14,7 @@ import net.momirealms.craftengine.core.block.properties.IntegerProperty; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.loot.parameter.LootParameters; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.RandomUtils; import net.momirealms.craftengine.core.util.Tuple; @@ -203,7 +204,7 @@ public class SugarCaneBlockBehavior extends BushBlockBehavior { Tuple, Set, Set> tuple = readTagsAndState(arguments, false); Property ageProperty = (Property) block.getProperty("age"); if (ageProperty == null) { - throw new IllegalArgumentException("age property not set for sugar cane"); + throw new LocalizedResourceConfigException("warning.config.block.behavior.sugar_cane.lack_age", new IllegalArgumentException("'age' property not set for sugar cane block behavior")); } int maxHeight = MiscUtils.getAsInt(arguments.getOrDefault("max-height", 3)); List nearbyLiquids = MiscUtils.getAsStringList(arguments.getOrDefault("required-adjacent-liquids", List.of())); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java index 01ccba6fe..477933c58 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java @@ -28,7 +28,7 @@ import net.momirealms.craftengine.core.pack.model.select.ChargeTypeSelectPropert import net.momirealms.craftengine.core.pack.model.select.TrimMaterialSelectProperty; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; -import net.momirealms.craftengine.core.plugin.locale.TranslationManager; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.WritableRegistry; @@ -240,11 +240,10 @@ public class BukkitItemManager extends AbstractItemManager { @Override public void parseSection(Pack pack, Path path, Key id, Map section) { if (customItems.containsKey(id)) { - TranslationManager.instance().log("warning.config.item.duplicated", path.toString(), id.toString()); - return; + throw new LocalizedResourceConfigException("warning.config.item.duplicated", path, id); } - // just register for recipes + // register for recipes Holder.Reference holder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(id) .orElseGet(() -> ((WritableRegistry) BuiltInRegistries.OPTIMIZED_ITEM_ID) .register(new ResourceKey<>(BuiltInRegistries.OPTIMIZED_ITEM_ID.key().location(), id), id)); @@ -254,14 +253,12 @@ public class BukkitItemManager extends AbstractItemManager { if (isVanillaItem) materialStringId = id.value(); if (materialStringId == null) { - TranslationManager.instance().log("warning.config.item.lack_material", path.toString(), id.toString()); - return; + throw new LocalizedResourceConfigException("warning.config.item.lack_material", path, id); } Material material = MaterialUtils.getMaterial(materialStringId); if (material == null) { - TranslationManager.instance().log("warning.config.item.invalid_material", path.toString(), id.toString(), materialStringId); - return; + throw new LocalizedResourceConfigException("warning.config.item.invalid_material", path, id); } Key materialId = Key.of(material.getKey().namespace(), material.getKey().value()); @@ -399,12 +396,11 @@ public class BukkitItemManager extends AbstractItemManager { // check conflict Map conflict = cmdConflictChecker.computeIfAbsent(materialId, k -> new HashMap<>()); if (conflict.containsKey(customModelData)) { - TranslationManager.instance().log("warning.config.item.custom_model_data_conflict", path.toString(), id.toString(), String.valueOf(customModelData), conflict.get(customModelData).toString()); - return; + throw new LocalizedResourceConfigException("warning.config.item.custom_model_data_conflict", path, id, String.valueOf(customModelData), conflict.get(customModelData).toString()); } if (customModelData > 16_777_216) { - TranslationManager.instance().log("warning.config.item.bad_custom_model_data_value", path.toString(), id.toString(), String.valueOf(customModelData)); + throw new LocalizedResourceConfigException("warning.config.item.bad_custom_model_data_value", path, id, String.valueOf(customModelData)); } conflict.put(customModelData, id); @@ -451,7 +447,7 @@ public class BukkitItemManager extends AbstractItemManager { } } if (!hasModel) { - TranslationManager.instance().log("warning.config.item.lack_model_id", path.toString(), id.toString()); + throw new LocalizedResourceConfigException("warning.config.item.lack_model_id", path, id); } } } 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 c778d1de2..76e259402 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 @@ -20,6 +20,7 @@ import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.pack.Pack; 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.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.world.BlockPos; @@ -187,7 +188,7 @@ public class BlockItemBehavior extends ItemBehavior { public ItemBehavior create(Pack pack, Path path, Key key, Map arguments) { Object id = arguments.get("block"); if (id == null) { - throw new IllegalArgumentException("Missing required parameter 'block' for block_item behavior"); + throw new LocalizedResourceConfigException("warning.config.item.behavior.block.lack_block", new IllegalArgumentException("Missing required parameter 'block' for block_item behavior")); } if (id instanceof Map map) { if (map.containsKey(key.toString())) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java index ca01dba72..219afd0cd 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FurnitureItemBehavior.java @@ -19,6 +19,7 @@ import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.collision.AABB; @@ -154,7 +155,7 @@ public class FurnitureItemBehavior extends ItemBehavior { public ItemBehavior create(Pack pack, Path path, Key key, Map arguments) { Object id = arguments.get("furniture"); if (id == null) { - throw new IllegalArgumentException("Missing required parameter 'furniture' for furniture_item behavior"); + throw new LocalizedResourceConfigException("warning.config.item.behavior.furniture.lack_furniture", new IllegalArgumentException("Missing required parameter 'furniture' for furniture_item behavior")); } if (id instanceof Map map) { if (map.containsKey(key.toString())) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/LiquidCollisionBlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/LiquidCollisionBlockItemBehavior.java index 3e35bc7df..14c1762a2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/LiquidCollisionBlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/LiquidCollisionBlockItemBehavior.java @@ -12,6 +12,7 @@ import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; @@ -63,7 +64,7 @@ public class LiquidCollisionBlockItemBehavior extends BlockItemBehavior { public ItemBehavior create(Pack pack, Path path, Key key, Map arguments) { Object id = arguments.get("block"); if (id == null) { - throw new IllegalArgumentException("Missing required parameter 'block' for liquid_collision_block_item behavior"); + throw new LocalizedResourceConfigException("warning.config.item.behavior.liquid_collision_block.lack_block", new IllegalArgumentException("Missing required parameter 'block' for liquid_collision_block_item behavior")); } int offset = MiscUtils.getAsInt(arguments.getOrDefault("y-offset", 1)); if (id instanceof Map map) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java index ef2800849..19bc6bd07 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java @@ -15,7 +15,7 @@ import net.momirealms.craftengine.core.loot.parameter.LootParameters; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; -import net.momirealms.craftengine.core.plugin.locale.TranslationManager; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.VersionHelper; @@ -110,8 +110,7 @@ public class BukkitVanillaLootManager extends AbstractVanillaLootManager impleme public void parseSection(Pack pack, Path path, Key id, Map section) { String type = (String) section.get("type"); if (type == null) { - TranslationManager.instance().log("warning.config.vanilla_loot.type_not_exist", path.toString(), id.toString()); - return; + throw new LocalizedResourceConfigException("warning.config.vanilla_loot.type_not_exist", path, id); } VanillaLoot.Type typeEnum = VanillaLoot.Type.valueOf(type.toUpperCase(Locale.ENGLISH)); boolean override = (boolean) section.getOrDefault("override", false); @@ -123,16 +122,14 @@ public class BukkitVanillaLootManager extends AbstractVanillaLootManager impleme if (target.endsWith("]") && target.contains("[")) { java.lang.Object blockState = BlockStateUtils.blockDataToBlockState(Bukkit.createBlockData(target)); if (blockState == Reflections.instance$Blocks$AIR$defaultState) { - TranslationManager.instance().log("warning.config.vanilla_loot.block.invalid_target", path.toString(), id.toString(), target); - return; + throw new LocalizedResourceConfigException("warning.config.vanilla_loot.block.invalid_target", path, id, target); } VanillaLoot vanillaLoot = blockLoots.computeIfAbsent(BlockStateUtils.blockStateToId(blockState), k -> new VanillaLoot(VanillaLoot.Type.BLOCK)); vanillaLoot.addLootTable(lootTable); } else { for (Object blockState : BlockStateUtils.getAllVanillaBlockStates(Key.of(target))) { if (blockState == Reflections.instance$Blocks$AIR$defaultState) { - TranslationManager.instance().log("warning.config.vanilla_loot.block.invalid_target", path.toString(), id.toString(), target); - return; + throw new LocalizedResourceConfigException("warning.config.vanilla_loot.block.invalid_target", path, id, target); } VanillaLoot vanillaLoot = blockLoots.computeIfAbsent(BlockStateUtils.blockStateToId(blockState), k -> new VanillaLoot(VanillaLoot.Type.BLOCK)); if (override) vanillaLoot.override(true); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockSettings.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockSettings.java index b4c5efafc..6a0e50b7f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockSettings.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockSettings.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.core.block; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.*; import org.jetbrains.annotations.Nullable; @@ -54,7 +55,7 @@ public class BlockSettings { if (factory != null) { factory.createModifier(entry.getValue()).apply(settings); } else { - throw new IllegalArgumentException("Unknown block settings key: " + entry.getKey()); + throw new LocalizedResourceConfigException("warning.config.block.settings.unknown", new IllegalArgumentException("Unknown block settings key: " + entry.getKey()), entry.getKey()); } } return settings; 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 54727da4d..1c9014b3e 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 @@ -31,14 +31,14 @@ public abstract class CustomBlock { @Nullable protected final LootTable lootTable; - public CustomBlock( + protected CustomBlock( @NotNull Key id, @NotNull Holder.Reference holder, @NotNull Map> properties, @NotNull Map appearances, @NotNull Map variantMapper, @NotNull BlockSettings settings, - @Nullable Map behaviorSettings, + @Nullable Map behavior, @Nullable LootTable lootTable ) { holder.bindValue(this); @@ -49,7 +49,7 @@ public abstract class CustomBlock { this.placements = new ArrayList<>(); this.variantProvider = new BlockStateVariantProvider(holder, ImmutableBlockState::new, properties); this.defaultState = this.variantProvider.getDefaultState(); - this.behavior = BlockBehaviors.fromMap(this, behaviorSettings); + this.behavior = BlockBehaviors.fromMap(this, behavior); for (Map.Entry entry : variantMapper.entrySet()) { String nbtString = entry.getKey(); CompoundTag tag = BlockNbtParser.deserialize(this, nbtString); @@ -159,4 +159,78 @@ public abstract class CustomBlock { } return state; } + + public abstract static class Builder { + protected final Key id; + protected Map> properties; + protected Map appearances; + protected Map variantMapper; + protected BlockSettings settings; + protected Map behavior; + protected LootTable lootTable; + + protected Builder(Key id) { + this.id = id; + } + + public Builder appearances(Map appearances) { + this.appearances = appearances; + return this; + } + + public Builder behavior(Map behaviorSettings) { + this.behavior = behaviorSettings; + return this; + } + + public Builder lootTable(LootTable lootTable) { + this.lootTable = lootTable; + return this; + } + + public Builder properties(Map> properties) { + this.properties = properties; + return this; + } + + public Builder settings(BlockSettings settings) { + this.settings = settings; + return this; + } + + public Builder variantMapper(Map variantMapper) { + this.variantMapper = variantMapper; + return this; + } + + public Map appearances() { + return appearances; + } + + public Map behavior() { + return behavior; + } + + public Key id() { + return id; + } + + public LootTable lootTable() { + return lootTable; + } + + public Map> properties() { + return properties; + } + + public BlockSettings settings() { + return settings; + } + + public Map variantMapper() { + return variantMapper; + } + + public abstract CustomBlock build(); + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/behavior/BlockBehaviors.java b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/BlockBehaviors.java index 5cbc64295..619336ee9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/behavior/BlockBehaviors.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/BlockBehaviors.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.core.block.behavior; import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; @@ -31,7 +32,7 @@ public class BlockBehaviors { Key key = Key.withDefaultNamespace(type, "craftengine"); BlockBehaviorFactory factory = BuiltInRegistries.BLOCK_BEHAVIOR_FACTORY.getValue(key); if (factory == null) { - throw new IllegalArgumentException("Unknown behavior type: " + type); + throw new LocalizedResourceConfigException("warning.config.block.behavior.invalid_type", new IllegalArgumentException("Unknown block behavior type: " + type), type); } return factory.create(block, map); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java index 60bcb92b4..4917c85d0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java @@ -7,6 +7,7 @@ import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.pack.ResourceLocation; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.util.context.ContextHolder; @@ -15,6 +16,10 @@ import org.ahocorasick.trie.Token; import org.ahocorasick.trie.Trie; import org.jetbrains.annotations.NotNull; +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; @@ -352,19 +357,16 @@ public abstract class AbstractFontManager implements FontManager { @Override public void parseSection(Pack pack, Path path, Key id, Map section) { if (emojis.containsKey(id)) { - TranslationManager.instance().log("warning.config.emoji.duplicated", path.toString(), id.toString()); - return; + throw new LocalizedResourceConfigException("warning.config.emoji.duplicated", path, id); } String permission = (String) section.get("permission"); Object keywordsRaw = section.get("keywords"); if (keywordsRaw == null) { - TranslationManager.instance().log("warning.config.emoji.lack_keywords", path.toString(), id.toString()); - return; + throw new LocalizedResourceConfigException("warning.config.emoji.lack_keywords", path, id); } List keywords = MiscUtils.getAsStringList(keywordsRaw); if (keywords.isEmpty()) { - TranslationManager.instance().log("warning.config.emoji.lack_keywords", path.toString(), id.toString()); - return; + throw new LocalizedResourceConfigException("warning.config.emoji.lack_keywords", path, id); } String content = section.getOrDefault("content", "").toString(); String image = null; @@ -377,8 +379,7 @@ public abstract class AbstractFontManager implements FontManager { if (bitmapImage.isPresent()) { image = bitmapImage.get().miniMessage(0, 0); } else { - TranslationManager.instance().log("warning.config.emoji.invalid_image", path.toString(), id.toString(), rawImage); - return; + throw new LocalizedResourceConfigException("warning.config.emoji.invalid_image", path, id, rawImage); } } else if (split.length == 4) { Key imageId = new Key(split[0], split[1]); @@ -387,16 +388,13 @@ public abstract class AbstractFontManager implements FontManager { try { image = bitmapImage.get().miniMessage(Integer.parseInt(split[2]), Integer.parseInt(split[3])); } catch (ArrayIndexOutOfBoundsException e) { - TranslationManager.instance().log("warning.config.emoji.invalid_image", path.toString(), id.toString(), rawImage); - return; + throw new LocalizedResourceConfigException("warning.config.emoji.invalid_image", path, id, rawImage); } } else { - TranslationManager.instance().log("warning.config.emoji.invalid_image", path.toString(), id.toString(), rawImage); - return; + throw new LocalizedResourceConfigException("warning.config.emoji.invalid_image", path, id, rawImage); } } else { - TranslationManager.instance().log("warning.config.emoji.invalid_image", path.toString(), id.toString(), rawImage); - return; + throw new LocalizedResourceConfigException("warning.config.emoji.invalid_image", path, id, rawImage); } } Emoji emoji = new Emoji(content, permission, image, keywords); @@ -420,39 +418,55 @@ public abstract class AbstractFontManager implements FontManager { @Override public void parseSection(Pack pack, Path path, Key id, Map section) { if (images.containsKey(id)) { - TranslationManager.instance().log("warning.config.image.duplicated", path.toString(), id.toString()); - return; + throw new LocalizedResourceConfigException("error.config.image.duplicated", path, id); + } + + Object file = section.get("file"); + if (file == null) { + throw new LocalizedResourceConfigException("warning.config.image.lack_file", path, id); + } + + String resourceLocation = file.toString().replace("\\", "/"); + if (!ResourceLocation.isValid(resourceLocation)) { + throw new LocalizedResourceConfigException("warning.config.image.invalid_resource_location", path, id, resourceLocation); + } + + String fontName = (String) section.getOrDefault("font", "minecraft:default"); + if (!ResourceLocation.isValid(fontName)) { + throw new LocalizedResourceConfigException("warning.config.image.invalid_font_name", path, id, fontName); } Object heightObj = section.get("height"); + + if (!resourceLocation.endsWith(".png")) resourceLocation += ".png"; + Key namespacedPath = Key.of(resourceLocation); + Path targetImagePath = pack.resourcePackFolder() + .resolve("assets") + .resolve(namespacedPath.namespace()) + .resolve("textures") + .resolve(namespacedPath.value()); + + if (!Files.exists(targetImagePath)) { + TranslationManager.instance().log("warning.config.image.file_not_exist", path.toString(), id.toString(), targetImagePath.toString()); + // DO NOT RETURN, JUST GIVE WARNINGS + } else if (heightObj == null) { + try (InputStream in = Files.newInputStream(targetImagePath)) { + BufferedImage image = ImageIO.read(in); + heightObj = image.getHeight(); + } catch (IOException e) { + plugin.logger().warn("Failed to load image " + targetImagePath, e); + return; + } + } + if (heightObj == null) { - TranslationManager.instance().log("warning.config.image.lack_height", path.toString(), id.toString()); - return; + throw new LocalizedResourceConfigException("warning.config.image.lack_height", path, id); } int height = MiscUtils.getAsInt(heightObj); int ascent = MiscUtils.getAsInt(section.getOrDefault("ascent", height - 1)); if (height < ascent) { - TranslationManager.instance().log("warning.config.image.height_smaller_than_ascent", path.toString(), id.toString()); - return; - } - - Object file = section.get("file"); - if (file == null) { - TranslationManager.instance().log("warning.config.image.no_file", path.toString(), id.toString()); - return; - } - - String resourceLocation = file.toString().replace("\\", "/"); - if (!ResourceLocation.isValid(resourceLocation)) { - TranslationManager.instance().log("warning.config.image.invalid_resource_location", path.toString(), id.toString(), resourceLocation); - return; - } - - String fontName = (String) section.getOrDefault("font", "minecraft:default"); - if (!ResourceLocation.isValid(fontName)) { - TranslationManager.instance().log("warning.config.image.invalid_font_name", path.toString(), id.toString(), fontName); - return; + throw new LocalizedResourceConfigException("warning.config.image.height_smaller_than_ascent", path, id); } Key fontKey = Key.withDefaultNamespace(fontName, id.namespace()); @@ -469,8 +483,7 @@ public abstract class AbstractFontManager implements FontManager { } else { Object c = section.get("char"); if (c == null) { - TranslationManager.instance().log("warning.config.image.lack_char", path.toString(), id.toString()); - return; + throw new LocalizedResourceConfigException("warning.config.image.lack_char", path, id); } if (c instanceof Integer integer) { chars = List.of(new char[]{(char) integer.intValue()}); @@ -491,42 +504,23 @@ public abstract class AbstractFontManager implements FontManager { for (int codepoint : codepoints) { if (font.isCodepointInUse(codepoint)) { BitmapImage image = font.bitmapImageByCodepoint(codepoint); - TranslationManager.instance().log("warning.config.image.codepoint_in_use", - path.toString(), - id.toString(), + throw new LocalizedResourceConfigException("warning.config.image.codepoint_in_use", path, id, fontKey.toString(), CharacterUtils.encodeCharsToUnicode(Character.toChars(codepoint)), new String(Character.toChars(codepoint)), - image.id().toString() - ); - return; + image.id().toString()); } } if (codepoints.length == 0) { - TranslationManager.instance().log("warning.config.image.lack_char", path.toString(), id.toString()); - return; + throw new LocalizedResourceConfigException("warning.config.image.lack_char", path, id); } codepointGrid[i] = codepoints; if (size == -1) size = codepoints.length; if (size != codepoints.length) { - TranslationManager.instance().log("warning.config.image.invalid_codepoint_grid", path.toString(), id.toString()); - return; + throw new LocalizedResourceConfigException("warning.config.image.invalid_codepoint_grid", path, id); } } - if (!resourceLocation.endsWith(".png")) resourceLocation += ".png"; - Key namespacedPath = Key.of(resourceLocation); - Path targetImagePath = pack.resourcePackFolder() - .resolve("assets") - .resolve(namespacedPath.namespace()) - .resolve("textures") - .resolve(namespacedPath.value()); - - if (!Files.exists(targetImagePath)) { - TranslationManager.instance().log("warning.config.image.file_not_exist", path.toString(), id.toString(), targetImagePath.toString()); - // DO NOT RETURN, JUST GIVE WARNINGS - } - BitmapImage bitmapImage = new BitmapImage(id, fontKey, height, ascent, resourceLocation, codepointGrid); for (int[] y : codepointGrid) { for (int x : y) { 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 b491baf28..691ad0307 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 @@ -1,6 +1,7 @@ package net.momirealms.craftengine.core.item.behavior; import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; @@ -21,14 +22,14 @@ public class ItemBehaviors { } public static ItemBehavior fromMap(Pack pack, Path path, Key id, Map map) { - String type = (String) map.getOrDefault("type", "empty"); + Object type = map.get("type"); if (type == null) { - throw new NullPointerException("behavior type cannot be null"); + throw new LocalizedResourceConfigException("warning.config.item.behavior.lack_type", new NullPointerException("behavior type cannot be null")); } - Key key = Key.withDefaultNamespace(type, "craftengine"); + Key key = Key.withDefaultNamespace(type.toString(), "craftengine"); ItemBehaviorFactory factory = BuiltInRegistries.ITEM_BEHAVIOR_FACTORY.getValue(key); if (factory == null) { - throw new IllegalArgumentException("Unknown behavior type: " + type); + throw new LocalizedResourceConfigException("warning.config.item.behavior.invalid_type", new IllegalArgumentException("Unknown behavior type: " + type), type.toString()); } return factory.create(pack, path, id, map); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java index 6f55615cf..1c13e04db 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java @@ -10,7 +10,7 @@ import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; -import net.momirealms.craftengine.core.plugin.locale.TranslationManager; +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.craftengine.core.util.VersionHelper; @@ -157,8 +157,7 @@ public abstract class AbstractRecipeManager implements RecipeManager { public void parseSection(Pack pack, Path path, Key id, Map section) { if (!Config.enableRecipeSystem()) return; if (AbstractRecipeManager.this.byId.containsKey(id)) { - TranslationManager.instance().log("warning.config.recipe.duplicated", path.toString(), id.toString()); - return; + throw new LocalizedResourceConfigException("warning.config.recipe.duplicated", path, id); } Recipe recipe; try { diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/number/NumberProviders.java b/core/src/main/java/net/momirealms/craftengine/core/loot/number/NumberProviders.java index 45ec409e9..277a9be23 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/number/NumberProviders.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/number/NumberProviders.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.core.loot.number; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; @@ -38,12 +39,12 @@ public class NumberProviders { public static NumberProvider fromMap(Map map) { String type = (String) map.get("type"); if (type == null) { - throw new NullPointerException("number type cannot be null"); + throw new LocalizedResourceConfigException("warning.config.loot_table.number.lack_type", new NullPointerException("number type cannot be null")); } Key key = Key.withDefaultNamespace(type, "craftengine"); NumberProviderFactory factory = BuiltInRegistries.NUMBER_PROVIDER_FACTORY.getValue(key); if (factory == null) { - throw new IllegalArgumentException("Unknown number type: " + type); + throw new LocalizedResourceConfigException("warning.config.loot_table.number.invalid_type", new IllegalArgumentException("Unknown number type: " + type), type); } return factory.create(map); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/BaseItemModel.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/BaseItemModel.java index 7b85ef0d8..07cee9b30 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/BaseItemModel.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/BaseItemModel.java @@ -2,9 +2,11 @@ package net.momirealms.craftengine.core.pack.model; import com.google.gson.JsonArray; import com.google.gson.JsonObject; +import net.momirealms.craftengine.core.pack.ResourceLocation; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.pack.model.tint.Tint; import net.momirealms.craftengine.core.pack.model.tint.Tints; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import org.jetbrains.annotations.Nullable; @@ -68,7 +70,14 @@ public class BaseItemModel implements ItemModel { @SuppressWarnings("unchecked") @Override public ItemModel create(Map arguments) { - String modelPath = Objects.requireNonNull(arguments.get("path"), "'path' is required for 'minecraft:model'. Current arguments: "+ arguments).toString(); + Object path = arguments.get("path"); + if (path == null) { + throw new LocalizedResourceConfigException("warning.config.item.model.base.lack_path", new NullPointerException("'path' is required for 'minecraft:model'")); + } + String modelPath = path.toString(); + if (!ResourceLocation.isValid(modelPath)) { + throw new LocalizedResourceConfigException("warning.config.item.model.base.invalid_resource_location", new IllegalArgumentException("Invalid resource location: " + modelPath), modelPath); + } Map generation = MiscUtils.castToMap(arguments.get("generation"), true); ModelGeneration modelGeneration = null; if (generation != null) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/CompositeItemModel.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/CompositeItemModel.java index 58487f35e..bed90211b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/CompositeItemModel.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/CompositeItemModel.java @@ -3,7 +3,10 @@ package net.momirealms.craftengine.core.pack.model; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; +import net.momirealms.craftengine.core.plugin.locale.LocalizedException; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; import java.util.ArrayList; import java.util.List; @@ -52,15 +55,22 @@ public class CompositeItemModel implements ItemModel { @SuppressWarnings("unchecked") @Override public ItemModel create(Map arguments) { - List> models = (List>) arguments.get("models"); - if (models == null || models.isEmpty()) { - throw new IllegalArgumentException("No 'models' specified for 'minecraft:composite'"); + Object m = arguments.get("models"); + if (m instanceof List list) { + List> models = (List>) list; + if (models.isEmpty()) { + throw new LocalizedResourceConfigException("warning.config.item.model.composite.lack_models", new IllegalArgumentException("'models' list should not be empty for 'minecraft:composite'")); + } + List modelList = new ArrayList<>(); + for (Map model : models) { + modelList.add(ItemModels.fromMap(model)); + } + return new CompositeItemModel(modelList); + } else if (m instanceof Map map) { + return new CompositeItemModel(List.of(ItemModels.fromMap(MiscUtils.castToMap(map, false)))); + } else { + throw new LocalizedResourceConfigException("warning.config.item.model.composite.lack_models", new NullPointerException("'models' argument is required for 'minecraft:composite'")); } - List modelList = new ArrayList<>(); - for (Map model : models) { - modelList.add(ItemModels.fromMap(model)); - } - return new CompositeItemModel(modelList); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/ConditionItemModel.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/ConditionItemModel.java index f30d9878f..514f0e4af 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/ConditionItemModel.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/ConditionItemModel.java @@ -4,7 +4,9 @@ import com.google.gson.JsonObject; import net.momirealms.craftengine.core.pack.model.condition.ConditionProperties; import net.momirealms.craftengine.core.pack.model.condition.ConditionProperty; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; import java.util.ArrayList; import java.util.List; @@ -60,13 +62,22 @@ public class ConditionItemModel implements ItemModel { public static class Factory implements ItemModelFactory { - @SuppressWarnings("unchecked") @Override public ItemModel create(Map arguments) { ConditionProperty property = ConditionProperties.fromMap(arguments); - Map onTrue = Objects.requireNonNull((Map) arguments.get("on-true"), "No 'on-true' set for 'minecraft:condition'"); - Map onFalse = Objects.requireNonNull((Map) arguments.get("on-false"), "No 'on-false' set for 'minecraft:condition'"); - return new ConditionItemModel(property, ItemModels.fromMap(onTrue), ItemModels.fromMap(onFalse)); + ItemModel onTrue; + if (arguments.get("on-true") instanceof Map map1) { + onTrue = ItemModels.fromMap(MiscUtils.castToMap(map1, false)); + } else { + throw new LocalizedResourceConfigException("warning.config.item.model.condition.lack_on_true", new NullPointerException("'on-true' is required for condition")); + } + ItemModel onFalse; + if (arguments.get("on-false") instanceof Map map2) { + onFalse = ItemModels.fromMap(MiscUtils.castToMap(map2, false)); + } else { + throw new LocalizedResourceConfigException("warning.config.item.model.condition.lack_on_false", new NullPointerException("'on-false' is required for condition")); + } + return new ConditionItemModel(property, onTrue, onFalse); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/ItemModels.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/ItemModels.java index 37df55401..70c199496 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/ItemModels.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/ItemModels.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.core.pack.model; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.registry.Registries; @@ -39,7 +40,7 @@ public class ItemModels { Key key = Key.withDefaultNamespace(type, "minecraft"); ItemModelFactory factory = BuiltInRegistries.ITEM_MODEL_FACTORY.getValue(key); if (factory == null) { - throw new IllegalArgumentException("Unknown model type: " + type); + throw new LocalizedResourceConfigException("warning.config.item.model.invalid_type", new IllegalArgumentException("Unknown model type: " + type), type); } return factory.create(map); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/RangeDispatchItemModel.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/RangeDispatchItemModel.java index 1efe99241..ae66d0020 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/RangeDispatchItemModel.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/RangeDispatchItemModel.java @@ -5,6 +5,7 @@ import com.google.gson.JsonObject; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.pack.model.rangedisptach.RangeDispatchProperties; import net.momirealms.craftengine.core.pack.model.rangedisptach.RangeDispatchProperty; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import org.jetbrains.annotations.NotNull; @@ -98,17 +99,26 @@ public class RangeDispatchItemModel implements ItemModel { RangeDispatchProperty property = RangeDispatchProperties.fromMap(arguments); float scale = MiscUtils.getAsFloat(arguments.getOrDefault("scale", 1.0)); Map fallback = MiscUtils.castToMap(arguments.get("fallback"), true); - List> entries = (List>) arguments.get("entries"); - if (entries != null && !entries.isEmpty()) { - Map entryMap = new HashMap<>(); - for (Map entry : entries) { - float threshold = MiscUtils.getAsFloat(entry.getOrDefault("threshold", 1)); - Map model = MiscUtils.castToMap(entry.getOrDefault("model", fallback), false); - entryMap.put(threshold, ItemModels.fromMap(model)); + Object entriesObj = arguments.get("entries"); + if (entriesObj instanceof List list) { + List> entries = (List>) list; + if (!entries.isEmpty()) { + Map entryMap = new HashMap<>(); + for (Map entry : entries) { + float threshold = MiscUtils.getAsFloat(entry.getOrDefault("threshold", 1)); + Object model = entry.getOrDefault("model", fallback); + if (model == null) { + throw new LocalizedResourceConfigException("warning.config.item.model.range_dispatch.entry.lack_model", new NullPointerException("'model' is required for range_dispatch entry")); + } + entryMap.put(threshold, ItemModels.fromMap(MiscUtils.castToMap(model, false))); + } + return new RangeDispatchItemModel(property, scale, fallback == null ? null : ItemModels.fromMap(fallback), entryMap); + } else { + throw new LocalizedResourceConfigException("warning.config.item.model.range_dispatch.lack_entries", new IllegalArgumentException("No entries found for range_dispatch")); } - return new RangeDispatchItemModel(property, scale, fallback == null ? null : ItemModels.fromMap(fallback), entryMap); + } else { + throw new LocalizedResourceConfigException("warning.config.item.model.range_dispatch.lack_entries", new NullPointerException("'entries' is required for the range_dispatch model")); } - throw new IllegalArgumentException("No 'entries' set for 'minecraft:range_dispatch'"); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/SelectItemModel.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/SelectItemModel.java index 38ed5829a..e303dd635 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/SelectItemModel.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/SelectItemModel.java @@ -5,6 +5,7 @@ import com.google.gson.JsonObject; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.pack.model.select.SelectProperties; import net.momirealms.craftengine.core.pack.model.select.SelectProperty; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import org.incendo.cloud.type.Either; @@ -96,28 +97,40 @@ public class SelectItemModel implements ItemModel { public ItemModel create(Map arguments) { SelectProperty property = SelectProperties.fromMap(arguments); Map fallback = MiscUtils.castToMap(arguments.get("fallback"), true); - List> cases = (List>) arguments.get("cases"); - if (cases != null && !cases.isEmpty()) { - Map>, ItemModel> whenMap = new HashMap<>(); - for (Map c : cases) { - Object when = c.get("when"); - if (when == null) continue; - Either> either; - if (when instanceof List whenList) { - List whens = new ArrayList<>(whenList.size()); - for (Object o : whenList) { - whens.add(o.toString()); + + Object casesObj = arguments.get("cases"); + if (casesObj instanceof List list) { + List> cases = (List>) list; + if (!cases.isEmpty()) { + Map>, ItemModel> whenMap = new HashMap<>(); + for (Map c : cases) { + Object when = c.get("when"); + if (when == null) { + throw new LocalizedResourceConfigException("warning.config.item.model.select.case.lack_when", new NullPointerException("'when' should not be null")); } - either = Either.ofFallback(whens); - } else { - either = Either.ofPrimary(when.toString()); + Either> either; + if (when instanceof List whenList) { + List whens = new ArrayList<>(whenList.size()); + for (Object o : whenList) { + whens.add(o.toString()); + } + either = Either.ofFallback(whens); + } else { + either = Either.ofPrimary(when.toString()); + } + Object model = c.get("model"); + if (model == null) { + throw new LocalizedResourceConfigException("warning.config.item.model.select.case.lack_model", new NullPointerException("'model' should not be null")); + } + whenMap.put(either, ItemModels.fromMap(MiscUtils.castToMap(model, false))); } - Map model = MiscUtils.castToMap(c.get("model"), false); - whenMap.put(either, ItemModels.fromMap(model)); + return new SelectItemModel(property, whenMap, fallback == null ? null : ItemModels.fromMap(fallback)); + } else { + throw new LocalizedResourceConfigException("warning.config.item.model.select.lack_cases", new NullPointerException("'cases' is required for the select model")); } - return new SelectItemModel(property, whenMap, fallback == null ? null : ItemModels.fromMap(fallback)); + } else { + throw new LocalizedResourceConfigException("warning.config.item.model.select.lack_cases", new NullPointerException("'cases' is required for the select model")); } - throw new IllegalArgumentException("No 'cases' set for 'minecraft:select'"); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/ModelGeneration.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/ModelGeneration.java index 51a7d16fc..29e49801e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/ModelGeneration.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/generation/ModelGeneration.java @@ -2,8 +2,12 @@ package net.momirealms.craftengine.core.pack.model.generation; import com.google.gson.JsonObject; import dev.dejvokep.boostedyaml.block.implementation.Section; +import net.momirealms.craftengine.core.pack.ResourceLocation; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; +import software.amazon.awssdk.services.s3.endpoints.internal.Value; import java.util.Collections; import java.util.LinkedHashMap; @@ -21,25 +25,13 @@ public class ModelGeneration { this.texturesOverride = texturesOverride; } - public ModelGeneration(Key path, Section section) { - this.path = path; - this.parentModelPath = Objects.requireNonNull(section.getString("parent")); - Section texturesSection = section.getSection("textures"); - if (texturesSection != null) { - this.texturesOverride = new LinkedHashMap<>(); - for (Map.Entry entry : texturesSection.getStringRouteMappedValues(false).entrySet()) { - if (entry.getValue() instanceof String p) { - this.texturesOverride.put(entry.getKey(), p); - } - } - } else { - this.texturesOverride = Collections.emptyMap(); - } - } - public ModelGeneration(Key path, Map map) { this.path = path; - this.parentModelPath = Objects.requireNonNull((String) map.get("parent")); + Object parent = map.get("parent"); + if (parent == null) { + throw new LocalizedResourceConfigException("warning.config.model.generation.lack_parent", new NullPointerException("'parent' argument is required for generation")); + } + this.parentModelPath = parent.toString(); Map texturesMap = MiscUtils.castToMap(map.get("textures"), true); if (texturesMap != null) { this.texturesOverride = new LinkedHashMap<>(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java index a3cb5abff..9731503ee 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java @@ -294,8 +294,7 @@ public class TranslationManagerImpl implements TranslationManager { public void parseSection(Pack pack, Path path, net.momirealms.craftengine.core.util.Key id, Map section) { Locale locale = TranslationManager.parseLocale(id.value()); if (locale == null) { - log("warning.config.i18n.unknown_locale", path.toString(), id.value()); - return; + throw new LocalizedResourceConfigException("warning.config.i18n.unknown_locale", path, id); } Map bundle = new HashMap<>(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/sound/AbstractSoundManager.java b/core/src/main/java/net/momirealms/craftengine/core/sound/AbstractSoundManager.java index 38ce5197e..d89413f9c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/sound/AbstractSoundManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/sound/AbstractSoundManager.java @@ -5,7 +5,7 @@ import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; -import net.momirealms.craftengine.core.plugin.locale.TranslationManager; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; @@ -78,13 +78,11 @@ public abstract class AbstractSoundManager implements SoundManager { @Override public void parseSection(Pack pack, Path path, Key id, Map section) { if (AbstractSoundManager.this.songs.containsKey(id)) { - TranslationManager.instance().log("warning.config.jukebox_song.duplicated", path.toString(), id.toString()); - return; + throw new LocalizedResourceConfigException("warning.config.jukebox_song.duplicated", path, id); } String sound = (String) section.get("sound"); if (sound == null) { - AbstractSoundManager.this.plugin.logger().warn(path, "No sound specified"); - return; + throw new LocalizedResourceConfigException("warning.config.jukebox_song.lack_sound", path, id); } Component description = AdventureHelper.miniMessage().deserialize(section.getOrDefault("description", "").toString()); float length = MiscUtils.getAsFloat(section.get("length")); @@ -110,8 +108,7 @@ public abstract class AbstractSoundManager implements SoundManager { @Override public void parseSection(Pack pack, Path path, Key id, Map section) { if (AbstractSoundManager.this.byId.containsKey(id)) { - TranslationManager.instance().log("warning.config.sound.duplicated", path.toString(), id.toString()); - return; + throw new LocalizedResourceConfigException("warning.config.sound.duplicated", path, id); } boolean replace = (boolean) section.getOrDefault("replace", false); String subtitle = (String) section.get("subtitle");