diff --git a/.gitmodules b/.gitmodules index b406eaf71..f225f3ed5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "wiki"] path = wiki url = https://github.com/Xiao-MoMi/craft-engine-wiki.git +[submodule "client-mod"] + path = client-mod + url = https://github.com/Xiao-MoMi/craft-engine-client-mod.git diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java index e21594b35..325159bdc 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java @@ -2,11 +2,13 @@ package net.momirealms.craftengine.bukkit.compatibility; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.block.entity.renderer.element.BukkitBlockEntityElementConfigs; import net.momirealms.craftengine.bukkit.compatibility.item.*; import net.momirealms.craftengine.bukkit.compatibility.legacy.slimeworld.LegacySlimeFormatStorageAdaptor; import net.momirealms.craftengine.bukkit.compatibility.leveler.*; +import net.momirealms.craftengine.bukkit.compatibility.model.bettermodel.BetterModelBlockEntityElementConfig; import net.momirealms.craftengine.bukkit.compatibility.model.bettermodel.BetterModelModel; -import net.momirealms.craftengine.bukkit.compatibility.model.bettermodel.BetterModelUtils; +import net.momirealms.craftengine.bukkit.compatibility.model.modelengine.ModelEngineBlockEntityElementConfig; import net.momirealms.craftengine.bukkit.compatibility.model.modelengine.ModelEngineModel; import net.momirealms.craftengine.bukkit.compatibility.model.modelengine.ModelEngineUtils; import net.momirealms.craftengine.bukkit.compatibility.mythicmobs.MythicItemDropListener; @@ -69,15 +71,6 @@ public class BukkitCompatibilityManager implements CompatibilityManager { @Override public void onEnable() { this.initSlimeWorldHook(); - if (this.isPluginEnabled("PlaceholderAPI")) { - PlaceholderAPIUtils.registerExpansions(this.plugin); - this.hasPlaceholderAPI = true; - logHook("PlaceholderAPI"); - } - if (this.isPluginEnabled("Skript")) { - SkriptHook.register(); - logHook("Skript"); - } // WorldEdit // FastAsyncWorldEdit if (this.isPluginEnabled("FastAsyncWorldEdit")) { @@ -91,16 +84,47 @@ public class BukkitCompatibilityManager implements CompatibilityManager { this.initWorldEditHook(); logHook("WorldEdit"); } + if (this.hasPlugin("BetterModel")) { + BukkitBlockEntityElementConfigs.register(Key.of("craftengine:better_model"), new BetterModelBlockEntityElementConfig.Factory()); + logHook("BetterModel"); + } + if (this.hasPlugin("ModelEngine")) { + BukkitBlockEntityElementConfigs.register(Key.of("craftengine:model_engine"), new ModelEngineBlockEntityElementConfig.Factory()); + logHook("ModelEngine"); + } + if (this.hasPlugin("CustomNameplates")) { + registerTagResolverProvider(new CustomNameplateProviders.Background()); + registerTagResolverProvider(new CustomNameplateProviders.Nameplate()); + registerTagResolverProvider(new CustomNameplateProviders.Bubble()); + logHook("CustomNameplates"); + } + Key worldGuardRegion = Key.of("worldguard:region"); + if (this.hasPlugin("WorldGuard")) { + EventConditions.register(worldGuardRegion, new WorldGuardRegionCondition.FactoryImpl<>()); + LootConditions.register(worldGuardRegion, new WorldGuardRegionCondition.FactoryImpl<>()); + logHook("WorldGuard"); + } else { + EventConditions.register(worldGuardRegion, new AlwaysFalseCondition.FactoryImpl<>()); + LootConditions.register(worldGuardRegion, new AlwaysFalseCondition.FactoryImpl<>()); + } } @Override public void onDelayedEnable() { + if (this.isPluginEnabled("PlaceholderAPI")) { + PlaceholderAPIUtils.registerExpansions(this.plugin); + this.hasPlaceholderAPI = true; + logHook("PlaceholderAPI"); + } this.initItemHooks(); - if (this.isPluginEnabled("LuckPerms")) { this.initLuckPermsHook(); logHook("LuckPerms"); } + if (this.isPluginEnabled("Skript")) { + SkriptHook.register(); + logHook("Skript"); + } if (this.isPluginEnabled("AuraSkills")) { this.registerLevelerProvider("AuraSkills", new AuraSkillsLevelerProvider()); logHook("AuraSkills"); @@ -133,33 +157,10 @@ public class BukkitCompatibilityManager implements CompatibilityManager { new MythicItemDropListener(this.plugin); logHook("MythicMobs"); } - Key worldGuardRegion = Key.of("worldguard:region"); - if (this.isPluginEnabled("WorldGuard")) { - EventConditions.register(worldGuardRegion, new WorldGuardRegionCondition.FactoryImpl<>()); - LootConditions.register(worldGuardRegion, new WorldGuardRegionCondition.FactoryImpl<>()); - logHook("WorldGuard"); - } else { - EventConditions.register(worldGuardRegion, new AlwaysFalseCondition.FactoryImpl<>()); - LootConditions.register(worldGuardRegion, new AlwaysFalseCondition.FactoryImpl<>()); - } - if (this.isPluginEnabled("BetterModel")) { - BetterModelUtils.registerConstantBlockEntityRender(); - logHook("BetterModel"); - } - if (this.isPluginEnabled("ModelEngine")) { - ModelEngineUtils.registerConstantBlockEntityRender(); - logHook("ModelEngine"); - } if (this.isPluginEnabled("QuickShop-Hikari")) { new QuickShopItemExpressionHandler(this.plugin).register(); logHook("QuickShop-Hikari"); } - if (this.isPluginEnabled("CustomNameplates")) { - registerTagResolverProvider(new CustomNameplateProviders.Background()); - registerTagResolverProvider(new CustomNameplateProviders.Nameplate()); - registerTagResolverProvider(new CustomNameplateProviders.Bubble()); - logHook("CustomNameplates"); - } } @Override @@ -233,7 +234,7 @@ public class BukkitCompatibilityManager implements CompatibilityManager { Bukkit.getPluginManager().registerEvents(adaptor, plugin.javaPlugin()); logHook("AdvancedSlimePaper"); } catch (ClassNotFoundException ignored) { - if (Bukkit.getPluginManager().isPluginEnabled("SlimeWorldPlugin")) { + if (hasPlugin("SlimeWorldPlugin")) { LegacySlimeFormatStorageAdaptor adaptor = new LegacySlimeFormatStorageAdaptor(worldManager, 2); worldManager.setStorageAdaptor(adaptor); Bukkit.getPluginManager().registerEvents(adaptor, plugin.javaPlugin()); diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/bettermodel/BetterModelUtils.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/bettermodel/BetterModelUtils.java index dbe86e340..6cbb90671 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/bettermodel/BetterModelUtils.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/bettermodel/BetterModelUtils.java @@ -2,11 +2,11 @@ package net.momirealms.craftengine.bukkit.compatibility.model.bettermodel; import kr.toxicity.model.api.BetterModel; import kr.toxicity.model.api.data.renderer.ModelRenderer; -import net.momirealms.craftengine.bukkit.block.entity.renderer.element.BukkitBlockEntityElementConfigs; -import net.momirealms.craftengine.core.util.Key; import org.bukkit.entity.Entity; -public class BetterModelUtils { +public final class BetterModelUtils { + + private BetterModelUtils() {} public static void bindModel(Entity base, String id) { ModelRenderer renderer = BetterModel.plugin().modelManager().model(id); @@ -15,8 +15,4 @@ public class BetterModelUtils { } renderer.create(base); } - - public static void registerConstantBlockEntityRender() { - BukkitBlockEntityElementConfigs.register(Key.of("craftengine:better_model"), new BetterModelBlockEntityElementConfig.Factory()); - } } diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/modelengine/ModelEngineBlockEntityElement.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/modelengine/ModelEngineBlockEntityElement.java index 0b49726b7..437e88f44 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/modelengine/ModelEngineBlockEntityElement.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/modelengine/ModelEngineBlockEntityElement.java @@ -11,7 +11,6 @@ import net.momirealms.craftengine.core.world.World; import org.bukkit.Location; import org.joml.Vector3f; -// TODO not tested yet public class ModelEngineBlockEntityElement implements BlockEntityElement { private Dummy dummy; private final Location location; @@ -41,14 +40,14 @@ public class ModelEngineBlockEntityElement implements BlockEntityElement { @Override public void hide(Player player) { if (this.dummy != null) { - this.dummy.setForceViewing((org.bukkit.entity.Player) player.platformPlayer(), true); + this.dummy.setForceHidden((org.bukkit.entity.Player) player.platformPlayer(), true); } } @Override public void show(Player player) { if (this.dummy != null) { - this.dummy.setForceHidden((org.bukkit.entity.Player) player.platformPlayer(), true); + this.dummy.setForceViewing((org.bukkit.entity.Player) player.platformPlayer(), true); } } diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/modelengine/ModelEngineUtils.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/modelengine/ModelEngineUtils.java index 156537804..9e45f1450 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/modelengine/ModelEngineUtils.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/modelengine/ModelEngineUtils.java @@ -3,11 +3,11 @@ package net.momirealms.craftengine.bukkit.compatibility.model.modelengine; import com.ticxo.modelengine.api.ModelEngineAPI; import com.ticxo.modelengine.api.model.ActiveModel; import com.ticxo.modelengine.api.model.ModeledEntity; -import net.momirealms.craftengine.bukkit.block.entity.renderer.element.BukkitBlockEntityElementConfigs; -import net.momirealms.craftengine.core.util.Key; import org.bukkit.entity.Entity; -public class ModelEngineUtils { +public final class ModelEngineUtils { + + private ModelEngineUtils() {} public static void bindModel(Entity base, String id) { ModeledEntity modeledEntity = ModelEngineAPI.createModeledEntity(base); @@ -26,8 +26,4 @@ public class ModelEngineUtils { } return entityId; } - - public static void registerConstantBlockEntityRender() { - BukkitBlockEntityElementConfigs.register(Key.of("craftengine:model_engine"), new ModelEngineBlockEntityElementConfig.Factory()); - } } diff --git a/bukkit/loader/build.gradle.kts b/bukkit/loader/build.gradle.kts index 2689dc4e7..2465542bb 100644 --- a/bukkit/loader/build.gradle.kts +++ b/bukkit/loader/build.gradle.kts @@ -44,14 +44,14 @@ tasks.withType { } bukkit { - load = net.minecrell.pluginyml.bukkit.BukkitPluginDescription.PluginLoadOrder.POSTWORLD + load = net.minecrell.pluginyml.bukkit.BukkitPluginDescription.PluginLoadOrder.STARTUP main = "net.momirealms.craftengine.bukkit.plugin.BukkitCraftEnginePlugin" version = rootProject.properties["project_version"] as String name = "CraftEngine" apiVersion = "1.20" authors = listOf("XiaoMoMi") contributors = listOf("https://github.com/Xiao-MoMi/craft-engine/graphs/contributors") - softDepend = listOf("PlaceholderAPI", "WorldEdit", "FastAsyncWorldEdit", "Skript") + softDepend = listOf("WorldEdit", "FastAsyncWorldEdit") foliaSupported = true } @@ -61,7 +61,7 @@ artifacts { tasks { shadowJar { - archiveFileName = "${rootProject.name}-${rootProject.properties["project_version"]}-community-bukkit.jar" + archiveFileName = "${rootProject.name}-bukkit-plugin-${rootProject.properties["project_version"]}.jar" destinationDirectory.set(file("$rootDir/target")) relocate("net.kyori", "net.momirealms.craftengine.libraries") relocate("net.momirealms.sparrow.nbt", "net.momirealms.craftengine.libraries.nbt") diff --git a/bukkit/loader/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEnginePlugin.java b/bukkit/loader/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEnginePlugin.java index 224703bfc..cbd3aacbe 100644 --- a/bukkit/loader/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEnginePlugin.java +++ b/bukkit/loader/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEnginePlugin.java @@ -19,8 +19,6 @@ public class BukkitCraftEnginePlugin extends JavaPlugin { @Override public void onEnable() { this.plugin.onPluginEnable(); - this.plugin.logger().warn("You're using the CraftEngine Community Edition."); - this.plugin.logger().warn("Please consider purchasing the premium version to support CraftEngine's development."); } @Override diff --git a/bukkit/paper-loader/build.gradle.kts b/bukkit/paper-loader/build.gradle.kts index d1281f320..38fe9e163 100644 --- a/bukkit/paper-loader/build.gradle.kts +++ b/bukkit/paper-loader/build.gradle.kts @@ -46,7 +46,7 @@ tasks.withType { } paper { - load = net.minecrell.pluginyml.bukkit.BukkitPluginDescription.PluginLoadOrder.POSTWORLD + load = net.minecrell.pluginyml.bukkit.BukkitPluginDescription.PluginLoadOrder.STARTUP main = "net.momirealms.craftengine.bukkit.plugin.PaperCraftEnginePlugin" bootstrapper = "net.momirealms.craftengine.bukkit.plugin.PaperCraftEngineBootstrap" version = rootProject.properties["project_version"] as String @@ -56,10 +56,7 @@ paper { contributors = listOf("https://github.com/Xiao-MoMi/craft-engine/graphs/contributors") foliaSupported = true serverDependencies { - register("PlaceholderAPI") { - required = false - load = PaperPluginDescription.RelativeLoadOrder.BEFORE - } + // WorldEdit register("WorldEdit") { required = false load = PaperPluginDescription.RelativeLoadOrder.BEFORE @@ -69,14 +66,18 @@ paper { load = PaperPluginDescription.RelativeLoadOrder.BEFORE joinClasspath = false } - register("Skript") { - required = false - load = PaperPluginDescription.RelativeLoadOrder.BEFORE - } + + register("PlaceholderAPI") { required = false } + register("Skript") { required = false } register("LuckPerms") { required = false } register("ViaVersion") { required = false } register("QuickShop-Hikari") { required = false } + // AdvancedSlimePaper + register("SlimeWorldPlugin") { required = false } + register("SlimeWorldManager") { required = false } + register("ASPaperPlugin") { required = false } + // external tag register("CustomNameplates") { required = false } @@ -143,7 +144,7 @@ tasks { manifest { attributes["paperweight-mappings-namespace"] = "mojang" } - archiveFileName = "${rootProject.name}-${rootProject.properties["project_version"]}-community-paper.jar" + archiveFileName = "${rootProject.name}-paper-plugin-${rootProject.properties["project_version"]}.jar" destinationDirectory.set(file("$rootDir/target")) relocate("net.kyori", "net.momirealms.craftengine.libraries") relocate("net.momirealms.sparrow.nbt", "net.momirealms.craftengine.libraries.nbt") diff --git a/bukkit/paper-loader/src/main/java/net/momirealms/craftengine/bukkit/plugin/PaperCraftEnginePlugin.java b/bukkit/paper-loader/src/main/java/net/momirealms/craftengine/bukkit/plugin/PaperCraftEnginePlugin.java index 58f7c9e8f..0840c777b 100644 --- a/bukkit/paper-loader/src/main/java/net/momirealms/craftengine/bukkit/plugin/PaperCraftEnginePlugin.java +++ b/bukkit/paper-loader/src/main/java/net/momirealms/craftengine/bukkit/plugin/PaperCraftEnginePlugin.java @@ -18,8 +18,6 @@ public final class PaperCraftEnginePlugin extends JavaPlugin { @Override public void onEnable() { this.bootstrap.plugin.onPluginEnable(); - this.bootstrap.plugin.logger().warn("You're using the CraftEngine Community Edition."); - this.bootstrap.plugin.logger().warn("Please consider purchasing the premium version to support CraftEngine's development."); } @Override 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 c5b38b1de..6f5161d72 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,9 +1,15 @@ package net.momirealms.craftengine.bukkit.block; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.LocationUtils; 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.block.ImmutableBlockState; +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.loot.LootTable; +import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.plugin.context.function.Function; @@ -13,6 +19,7 @@ import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Map; +import java.util.Optional; public final class BukkitCustomBlock extends AbstractCustomBlock { @@ -24,4 +31,19 @@ public final class BukkitCustomBlock extends AbstractCustomBlock { ) { super(holder, variantProvider, events, lootTable); } + + @Override + public void setPlacedBy(BlockPlaceContext context, ImmutableBlockState state) { + try { + this.behavior.placeMultiState(BlockStateUtils.getBlockOwner(state.customBlockState().literalObject()), new Object[]{ + context.getLevel().serverWorld(), + LocationUtils.toBlockPos(context.getClickedPos()), + state.customBlockState().literalObject(), + Optional.ofNullable(context.getPlayer()).map(Player::serverPlayer).orElse(null), + context.getItem().getLiteralObject() + }, () -> null); + } catch (Throwable t) { + CraftEngine.instance().logger().warn("Failed to run setPlacedBy ", t); + } + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlockStateWrapper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlockStateWrapper.java index b3370a11e..53d9cbfb0 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlockStateWrapper.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlockStateWrapper.java @@ -59,6 +59,15 @@ public class BukkitCustomBlockStateWrapper extends AbstractBlockStateWrapper imp return this; } + @Override + public BlockStateWrapper cycleProperty(String propertyName, boolean backwards) { + return getImmutableBlockState().map(state -> { + Property property = state.owner().value().getProperty(propertyName); + if (property == null) return null; + return state.cycle(property, backwards).customBlockState(); + }).orElse(this); + } + @Override public boolean hasProperty(String propertyName) { return getImmutableBlockState().map(state -> state.owner().value().getProperty(propertyName) != null).orElse(false); @@ -78,4 +87,9 @@ public class BukkitCustomBlockStateWrapper extends AbstractBlockStateWrapper imp public Optional getImmutableBlockState() { return BlockStateUtils.getOptionalCustomBlockState(super.blockState); } + + @Override + public boolean isAir() { + return false; + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitVanillaBlockStateWrapper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitVanillaBlockStateWrapper.java index b298f6d66..96d13edbd 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitVanillaBlockStateWrapper.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitVanillaBlockStateWrapper.java @@ -54,4 +54,16 @@ public class BukkitVanillaBlockStateWrapper extends AbstractBlockStateWrapper { if (newState == super.blockState) return this; return BlockRegistryMirror.byId(BlockStateUtils.blockStateToId(newState)); } + + @Override + public BlockStateWrapper cycleProperty(String propertyName, boolean backwards) { + Object newState = this.accessor.cycleProperty(propertyName, backwards); + if (newState == super.blockState) return this; + return BlockRegistryMirror.byId(BlockStateUtils.blockStateToId(newState)); + } + + @Override + public boolean isAir() { + return FastNMS.INSTANCE.method$BlockStateBase$isAir(super.blockState); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BouncingBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BouncingBlockBehavior.java index 87d709036..b29f312a7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BouncingBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BouncingBlockBehavior.java @@ -7,7 +7,7 @@ import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.core.block.BlockBehavior; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; -import net.momirealms.craftengine.core.block.behavior.special.FallOnBlockBehavior; +import net.momirealms.craftengine.core.block.behavior.FallOnBlockBehavior; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.VersionHelper; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java index 4bb3daf89..e819e7515 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java @@ -44,6 +44,8 @@ public class BukkitBlockBehaviors extends BlockBehaviors { public static final Key CHIME_BLOCK = Key.from("craftengine:chime_block"); public static final Key BUDDING_BLOCK = Key.from("craftengine:budding_block"); public static final Key SEAT_BLOCK = Key.from("craftengine:seat_block"); + public static final Key SURFACE_SPREADING_BLOCK = Key.from("craftengine:surface_spreading_block"); + public static final Key SNOWY_BLOCK = Key.from("craftengine:snowy_block"); public static void init() { register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE); @@ -86,5 +88,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors { register(CHIME_BLOCK, ChimeBlockBehavior.FACTORY); register(BUDDING_BLOCK, BuddingBlockBehavior.FACTORY); register(SEAT_BLOCK, SeatBlockBehavior.FACTORY); + register(SURFACE_SPREADING_BLOCK, SurfaceSpreadingBlockBehavior.FACTORY); + register(SNOWY_BLOCK, SnowyBlockBehavior.FACTORY); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoorBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoorBlockBehavior.java index 677e9dd1c..098092f9f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoorBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoorBlockBehavior.java @@ -169,9 +169,24 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior { } @Override - public void setPlacedBy(BlockPlaceContext context, ImmutableBlockState state) { - BlockPos pos = context.getClickedPos(); - context.getLevel().setBlockAt(pos.x(), pos.y() + 1, pos.z(), state.with(this.halfProperty, DoubleBlockHalf.UPPER).customBlockState(), UpdateOption.UPDATE_ALL.flags()); + public boolean canPlaceMultiState(BlockAccessor accessor, BlockPos pos, ImmutableBlockState state) { + if (pos.y() >= accessor.worldHeight().getMaxBuildHeight() - 1) { + return false; + } + return accessor.getBlockState(pos.above()).isAir(); + } + + @Override + public void placeMultiState(Object thisBlock, Object[] args, Callable superMethod) { + Object blockState = args[2]; + Object pos = args[1]; + Optional immutableBlockState = BlockStateUtils.getOptionalCustomBlockState(blockState); + immutableBlockState.ifPresent(state -> FastNMS.INSTANCE.method$LevelWriter$setBlock(args[0], LocationUtils.above(pos), state.with(this.halfProperty, DoubleBlockHalf.UPPER).customBlockState().literalObject(), UpdateOption.UPDATE_ALL.flags())); + } + + @Override + public boolean hasMultiState(ImmutableBlockState baseState) { + return baseState.get(this.halfProperty) == DoubleBlockHalf.LOWER; } @Override @@ -179,7 +194,7 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior { World world = context.getLevel(); Object level = world.serverWorld(); BlockPos pos = context.getClickedPos(); - if (pos.y() < context.getLevel().worldHeight().getMaxBuildHeight() && world.getBlockAt(pos.above()).canBeReplaced(context)) { + if (pos.y() < world.worldHeight().getMaxBuildHeight() - 1 && world.getBlock(pos.above()).canBeReplaced(context)) { boolean hasSignal = FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(level, LocationUtils.toBlockPos(pos)) || FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(level, LocationUtils.toBlockPos(pos.above())); return state.with(this.poweredProperty, hasSignal) .with(this.facingProperty, context.getHorizontalDirection().toHorizontalDirection()) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java index a60b2597f..a384ceb20 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java @@ -1,31 +1,38 @@ package net.momirealms.craftengine.bukkit.block.behavior; -import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.api.BukkitAdaptors; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks; +import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.DirectionUtils; import net.momirealms.craftengine.bukkit.util.LocationUtils; -import net.momirealms.craftengine.core.block.*; +import net.momirealms.craftengine.bukkit.world.BukkitWorld; +import net.momirealms.craftengine.core.block.BlockBehavior; +import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +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.block.properties.type.DoubleBlockHalf; +import net.momirealms.craftengine.core.entity.player.InteractionHand; +import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; -import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.ResourceConfigUtils; -import net.momirealms.craftengine.core.world.BlockPos; -import net.momirealms.craftengine.core.world.World; -import net.momirealms.craftengine.core.world.WorldEvents; +import net.momirealms.craftengine.core.world.*; +import org.bukkit.inventory.ItemStack; import java.util.Map; +import java.util.Optional; import java.util.concurrent.Callable; -public class DoubleHighBlockBehavior extends BukkitBlockBehavior { +public class DoubleHighBlockBehavior extends AbstractCanSurviveBlockBehavior { public static final Factory FACTORY = new Factory(); private final Property halfProperty; public DoubleHighBlockBehavior(CustomBlock customBlock, Property halfProperty) { - super(customBlock); + super(customBlock, 0); this.halfProperty = halfProperty; } @@ -34,40 +41,100 @@ public class DoubleHighBlockBehavior extends BukkitBlockBehavior { Object level = args[updateShape$level]; Object blockPos = args[updateShape$blockPos]; Object blockState = args[0]; - - ImmutableBlockState customState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState)); + ImmutableBlockState customState = BlockStateUtils.getOptionalCustomBlockState(blockState).orElse(null); if (customState == null || customState.isEmpty()) return blockState; DoubleBlockHalf half = customState.get(this.halfProperty); - if (half == null) return blockState; - - // 获取另一半 - Object anotherHalfPos = FastNMS.INSTANCE.method$BlockPos$relative(blockPos, - half == DoubleBlockHalf.UPPER - ? CoreReflections.instance$Direction$DOWN - : CoreReflections.instance$Direction$UP - ); - Object anotherHalfState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, anotherHalfPos); - ImmutableBlockState anotherHalfCustomState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(anotherHalfState)); - if (anotherHalfCustomState != null && !anotherHalfCustomState.isEmpty()) return blockState; - - // 破坏 - FastNMS.INSTANCE.method$LevelAccessor$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId()); - return MBlocks.AIR$defaultState; + Object direction = args[updateShape$direction]; + if (DirectionUtils.isYAxis(direction) && half == DoubleBlockHalf.LOWER == (direction == CoreReflections.instance$Direction$UP)) { + ImmutableBlockState neighborState = BlockStateUtils.getOptionalCustomBlockState(args[updateShape$neighborState]).orElse(null); + if (neighborState == null || neighborState.isEmpty()) return MBlocks.AIR$defaultState; + DoubleHighBlockBehavior anotherDoorBehavior = neighborState.behavior().getAs(DoubleHighBlockBehavior.class).orElse(null); + if (anotherDoorBehavior == null) return MBlocks.AIR$defaultState; + if (neighborState.get(anotherDoorBehavior.halfProperty) != half) { + return neighborState.with(anotherDoorBehavior.halfProperty, half).customBlockState().literalObject(); + } + return MBlocks.AIR$defaultState; + } else if (half == DoubleBlockHalf.LOWER && direction == CoreReflections.instance$Direction$DOWN && !canSurvive(thisBlock, blockState, level, blockPos)) { + BlockPos pos = LocationUtils.fromBlockPos(blockPos); + World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); + WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(pos)); + world.playBlockSound(position, customState.settings().sounds().breakSound()); + FastNMS.INSTANCE.method$LevelAccessor$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId()); + return MBlocks.AIR$defaultState; + } + return blockState; } @Override - public void setPlacedBy(BlockPlaceContext context, ImmutableBlockState state) { - World level = context.getLevel(); - BlockPos anotherHalfPos = context.getClickedPos().relative(Direction.UP); - BlockStateWrapper blockStateWrapper = state.with(this.halfProperty, DoubleBlockHalf.UPPER).customBlockState(); - FastNMS.INSTANCE.method$LevelWriter$setBlock(level.serverWorld(), LocationUtils.toBlockPos(anotherHalfPos), blockStateWrapper.literalObject(), UpdateOption.Flags.UPDATE_CLIENTS); + public Object playerWillDestroy(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Object level = args[0]; + Object pos = args[1]; + Object state = args[2]; + Object player = args[3]; + ImmutableBlockState blockState = BlockStateUtils.getOptionalCustomBlockState(state).orElse(null); + if (blockState == null || blockState.isEmpty()) return superMethod.call(); + BukkitServerPlayer cePlayer = BukkitAdaptors.adapt(FastNMS.INSTANCE.method$ServerPlayer$getBukkitEntity(player)); + Item item = cePlayer.getItemInHand(InteractionHand.MAIN_HAND); + if (cePlayer.canInstabuild() || !BlockStateUtils.isCorrectTool(blockState, item)) { + preventDropFromBottomPart(level, pos, blockState, player); + } + return superMethod.call(); + } + + private void preventDropFromBottomPart(Object level, Object pos, ImmutableBlockState state, Object player) { + if (state.get(this.halfProperty) != DoubleBlockHalf.UPPER) return; + Object blockPos = FastNMS.INSTANCE.method$BlockPos$relative(pos, CoreReflections.instance$Direction$DOWN); + Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, blockPos); + ImmutableBlockState belowState = BlockStateUtils.getOptionalCustomBlockState(blockState).orElse(null); + if (belowState == null || belowState.isEmpty()) return; + Optional belowDoubleHighBlockBehavior = belowState.behavior().getAs(DoubleHighBlockBehavior.class); + if (belowDoubleHighBlockBehavior.isEmpty() || belowState.get(this.halfProperty) != DoubleBlockHalf.LOWER) return; + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, MBlocks.AIR$defaultState, UpdateOption.builder().updateSuppressDrops().updateClients().updateNeighbors().build().flags()); + FastNMS.INSTANCE.method$LevelAccessor$levelEvent(level, player, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, belowState.customBlockState().registryId()); + } + + @Override + protected boolean canSurvive(Object thisBlock, Object state, Object world, Object blockPos) throws Exception { + ImmutableBlockState customState = BlockStateUtils.getOptionalCustomBlockState(state).orElse(null); + if (customState == null || customState.isEmpty()) return false; + if (customState.get(this.halfProperty) == DoubleBlockHalf.UPPER) { + int x = FastNMS.INSTANCE.field$Vec3i$x(blockPos); + int y = FastNMS.INSTANCE.field$Vec3i$y(blockPos) - 1; + int z = FastNMS.INSTANCE.field$Vec3i$z(blockPos); + Object belowPos = FastNMS.INSTANCE.constructor$BlockPos(x, y, z); + Object belowState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, belowPos); + Optional belowCustomState = BlockStateUtils.getOptionalCustomBlockState(belowState); + return belowCustomState.filter(immutableBlockState -> immutableBlockState.owner().value() == super.customBlock).isPresent(); + } + return true; + } + + @Override + public void placeMultiState(Object thisBlock, Object[] args, Callable superMethod) { + Object blockState = args[2]; + Object pos = args[1]; + Optional immutableBlockState = BlockStateUtils.getOptionalCustomBlockState(blockState); + immutableBlockState.ifPresent(state -> FastNMS.INSTANCE.method$LevelWriter$setBlock(args[0], LocationUtils.above(pos), state.with(this.halfProperty, DoubleBlockHalf.UPPER).customBlockState().literalObject(), UpdateOption.UPDATE_ALL.flags())); + } + + @Override + public boolean hasMultiState(ImmutableBlockState baseState) { + return baseState.get(this.halfProperty) == DoubleBlockHalf.LOWER; + } + + @Override + public boolean canPlaceMultiState(BlockAccessor accessor, BlockPos pos, ImmutableBlockState state) { + if (pos.y() >= accessor.worldHeight().getMaxBuildHeight() - 1) { + return false; + } + return accessor.getBlockState(pos.above()).isAir(); } @Override public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) { World world = context.getLevel(); BlockPos pos = context.getClickedPos(); - if (pos.y() < context.getLevel().worldHeight().getMaxBuildHeight() && world.getBlockAt(pos.above()).canBeReplaced(context)) { + if (pos.y() < context.getLevel().worldHeight().getMaxBuildHeight() - 1 && world.getBlock(pos.above()).canBeReplaced(context)) { return state.with(this.halfProperty, DoubleBlockHalf.LOWER); } return null; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceBlockBehavior.java index 4adb6c62e..520c7b37d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceBlockBehavior.java @@ -96,10 +96,10 @@ public class FenceBlockBehavior extends BukkitBlockBehavior { BlockPos blockPos1 = clickedPos.east(); BlockPos blockPos2 = clickedPos.south(); BlockPos blockPos3 = clickedPos.west(); - BlockStateWrapper blockState = level.getBlockAt(blockPos).blockState(); - BlockStateWrapper blockState1 = level.getBlockAt(blockPos1).blockState(); - BlockStateWrapper blockState2 = level.getBlockAt(blockPos2).blockState(); - BlockStateWrapper blockState3 = level.getBlockAt(blockPos3).blockState(); + BlockStateWrapper blockState = level.getBlock(blockPos).blockState(); + BlockStateWrapper blockState1 = level.getBlock(blockPos1).blockState(); + BlockStateWrapper blockState2 = level.getBlock(blockPos2).blockState(); + BlockStateWrapper blockState3 = level.getBlock(blockPos3).blockState(); BooleanProperty waterlogged = (BooleanProperty) state.owner().value().getProperty("waterlogged"); if (waterlogged != null) { state = state.with(waterlogged, FastNMS.INSTANCE.method$FluidState$getType(fluidState) == MFluids.WATER); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/GrassBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/GrassBlockBehavior.java index 6903885ef..d04773e38 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/GrassBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/GrassBlockBehavior.java @@ -86,7 +86,7 @@ public class GrassBlockBehavior extends BukkitBlockBehavior { if (ItemUtils.isEmpty(item) || !item.vanillaId().equals(ItemKeys.BONE_MEAL) || context.getPlayer().isAdventureMode()) return InteractionResult.PASS; BlockPos pos = context.getClickedPos(); - BukkitExistingBlock upper = (BukkitExistingBlock) context.getLevel().getBlockAt(pos.x(), pos.y() + 1, pos.z()); + BukkitExistingBlock upper = (BukkitExistingBlock) context.getLevel().getBlock(pos.x(), pos.y() + 1, pos.z()); Block block = upper.block(); if (!block.isEmpty()) return InteractionResult.PASS; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LiquidFlowableBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LiquidFlowableBlockBehavior.java index 65edd4bdc..764c1452a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LiquidFlowableBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LiquidFlowableBlockBehavior.java @@ -6,7 +6,7 @@ import net.momirealms.craftengine.core.block.BlockBehavior; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.UpdateOption; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; -import net.momirealms.craftengine.core.block.behavior.special.PlaceLiquidBlockBehavior; +import net.momirealms.craftengine.core.block.behavior.PlaceLiquidBlockBehavior; import net.momirealms.craftengine.core.world.WorldEvents; import java.util.Map; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SlabBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SlabBlockBehavior.java index f44f55c3a..cf3137dd0 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SlabBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SlabBlockBehavior.java @@ -60,7 +60,7 @@ public class SlabBlockBehavior extends BukkitBlockBehavior { @Override public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) { BlockPos clickedPos = context.getClickedPos(); - ImmutableBlockState blockState = context.getLevel().getBlockAt(clickedPos).customBlockState(); + ImmutableBlockState blockState = context.getLevel().getBlock(clickedPos).customBlockState(); if (blockState != null && blockState.owner().value() == super.customBlock) { if (super.waterloggedProperty != null) blockState = blockState.with(super.waterloggedProperty, false); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SnowyBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SnowyBlockBehavior.java new file mode 100644 index 000000000..c4ec18874 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SnowyBlockBehavior.java @@ -0,0 +1,55 @@ +package net.momirealms.craftengine.bukkit.block.behavior; + +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MTagKeys; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.LocationUtils; +import net.momirealms.craftengine.core.block.BlockBehavior; +import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.block.properties.BooleanProperty; +import net.momirealms.craftengine.core.item.context.BlockPlaceContext; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.Map; +import java.util.concurrent.Callable; + +public class SnowyBlockBehavior extends BukkitBlockBehavior { + public static final Factory FACTORY = new Factory(); + private final BooleanProperty snowyProperty; + + public SnowyBlockBehavior(CustomBlock customBlock, BooleanProperty snowyProperty) { + super(customBlock); + this.snowyProperty = snowyProperty; + } + + @Override + public Object updateShape(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + if (args[updateShape$direction] != CoreReflections.instance$Direction$UP) return superMethod.call(); + ImmutableBlockState state = BlockStateUtils.getOptionalCustomBlockState(args[0]).orElse(null); + if (state == null || state.isEmpty()) return superMethod.call(); + ImmutableBlockState newState = state.with(this.snowyProperty, isSnowySetting(args[updateShape$neighborState])); + return newState.customBlockState().literalObject(); + } + + @Override + public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) { + Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos().above())); + return state.with(this.snowyProperty, isSnowySetting(blockState)); + } + + private static boolean isSnowySetting(Object state) { + return FastNMS.INSTANCE.method$BlockStateBase$is(state, MTagKeys.Block$SNOW); + } + + public static class Factory implements BlockBehaviorFactory { + + @Override + public BlockBehavior create(CustomBlock block, Map arguments) { + BooleanProperty snowyProperty = (BooleanProperty) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("snowy"), "warning.config.block.behavior.snowy.missing_snowy"); + return new SnowyBlockBehavior(block, snowyProperty); + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SurfaceSpreadingBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SurfaceSpreadingBlockBehavior.java new file mode 100644 index 000000000..b0a67e4dd --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SurfaceSpreadingBlockBehavior.java @@ -0,0 +1,114 @@ +package net.momirealms.craftengine.bukkit.block.behavior; + +import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +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.MTagKeys; +import net.momirealms.craftengine.core.block.BlockBehavior; +import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +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.util.LazyReference; +import net.momirealms.craftengine.core.util.RandomUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.VersionHelper; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.Callable; + +public class SurfaceSpreadingBlockBehavior extends BukkitBlockBehavior { + public static final Factory FACTORY = new Factory(); + private final int requiredLight; + private final LazyReference baseBlock; + private final Property snowyProperty; + + public SurfaceSpreadingBlockBehavior(CustomBlock customBlock, int requiredLight, String baseBlock, @Nullable Property snowyProperty) { + super(customBlock); + this.requiredLight = requiredLight; + this.snowyProperty = snowyProperty; + this.baseBlock = LazyReference.lazyReference(() -> Objects.requireNonNull(BukkitBlockManager.instance().createBlockState(baseBlock)).literalObject()); + } + + @Override + public void randomTick(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Object state = args[0]; + Object level = args[1]; + Object pos = args[2]; + if (!canBeGrass(state, level, pos)) { + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, this.baseBlock.get(), 3); + return; + } + if (FastNMS.INSTANCE.method$LevelReader$getMaxLocalRawBrightness(level, FastNMS.INSTANCE.method$BlockPos$relative(pos, CoreReflections.instance$Direction$UP)) < this.requiredLight) return; + + for (int i = 0; i < 4; i++) { + Object blockPos = FastNMS.INSTANCE.method$BlockPos$offset( + pos, + RandomUtils.generateRandomInt(-1, 2), + RandomUtils.generateRandomInt(-3, 2), + RandomUtils.generateRandomInt(-1, 2) + ); + + if (FastNMS.INSTANCE.method$BlockStateBase$isBlock( + FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, blockPos), + FastNMS.INSTANCE.method$BlockState$getBlock(this.baseBlock.get()) + ) && canPropagate(state, level, blockPos)) { + + ImmutableBlockState newState = this.block().defaultState(); + + if (this.snowyProperty != null) { + boolean hasSnow = FastNMS.INSTANCE.method$BlockStateBase$isBlock( + FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, + FastNMS.INSTANCE.method$BlockPos$relative(blockPos, CoreReflections.instance$Direction$UP)), + MBlocks.SNOW + ); + newState = newState.with(this.snowyProperty, hasSnow); + } + + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, newState.customBlockState().literalObject(), UpdateOption.UPDATE_ALL.flags()); + } + } + } + + private static boolean canBeGrass(Object state, Object level, Object pos) { + Object blockPos = FastNMS.INSTANCE.method$BlockPos$relative(pos, CoreReflections.instance$Direction$UP); + Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, blockPos); + if (FastNMS.INSTANCE.method$BlockStateBase$isBlock(blockState, MBlocks.SNOW) && ((Integer) FastNMS.INSTANCE.method$StateHolder$getValue(blockState, CoreReflections.instance$SnowLayerBlock$LAYERS)) == 1) return true; + else if (FastNMS.INSTANCE.field$FluidState$amount(FastNMS.INSTANCE.field$BlockBehaviour$BlockStateBase$fluidState(blockState)) == 8) return false; + else { + return FastNMS.INSTANCE.method$LightEngine$getLightBlockInto( + VersionHelper.isOrAbove1_21_2() ? null : level, + state, + VersionHelper.isOrAbove1_21_2() ? null : pos, + blockState, + VersionHelper.isOrAbove1_21_2() ? null : blockPos, + CoreReflections.instance$Direction$UP, + FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getLightBlock( + blockState, + VersionHelper.isOrAbove1_21_2() ? null : level, + VersionHelper.isOrAbove1_21_2() ? null : pos + ) + ) < 15; + } + } + + private static boolean canPropagate(Object state, Object level, Object pos) { + Object blockPos = FastNMS.INSTANCE.method$BlockPos$relative(pos, CoreReflections.instance$Direction$UP); + return canBeGrass(state, level, pos) && !FastNMS.INSTANCE.method$FluidState$is(FastNMS.INSTANCE.method$BlockGetter$getFluidState(level, blockPos), MTagKeys.Fluid$WATER); + } + + public static class Factory implements BlockBehaviorFactory { + + @SuppressWarnings("unchecked") + @Override + public BlockBehavior create(CustomBlock block, Map arguments) { + int requiredLight = ResourceConfigUtils.getAsInt(arguments.getOrDefault("required-light", 9), "required-light"); + String baseBlock = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.getOrDefault("base-block", "minecraft:dirt"), "warning.config.block.behavior.surface_spreading.missing_base_block"); + return new SurfaceSpreadingBlockBehavior(block, requiredLight, baseBlock, (Property) block.getProperty("snowy")); + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/UnsafeCompositeBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/UnsafeCompositeBlockBehavior.java index be647e450..c487b4ab1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/UnsafeCompositeBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/UnsafeCompositeBlockBehavior.java @@ -4,11 +4,13 @@ import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior; import net.momirealms.craftengine.core.block.behavior.EntityBlockBehavior; -import net.momirealms.craftengine.core.block.behavior.special.FallOnBlockBehavior; -import net.momirealms.craftengine.core.block.behavior.special.PlaceLiquidBlockBehavior; +import net.momirealms.craftengine.core.block.behavior.FallOnBlockBehavior; +import net.momirealms.craftengine.core.block.behavior.PlaceLiquidBlockBehavior; import net.momirealms.craftengine.core.entity.player.InteractionResult; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.item.context.UseOnContext; +import net.momirealms.craftengine.core.world.BlockAccessor; +import net.momirealms.craftengine.core.world.BlockPos; import org.jetbrains.annotations.Nullable; import java.util.List; @@ -119,7 +121,6 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior return previous; } - @Override public Object getContainer(Object thisBlock, Object[] args) throws Exception { for (AbstractBlockBehavior behavior : this.behaviors) { @@ -251,13 +252,6 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior } } - @Override - public void setPlacedBy(BlockPlaceContext context, ImmutableBlockState state) { - for (AbstractBlockBehavior behavior : this.behaviors) { - behavior.setPlacedBy(context, state); - } - } - @Override public boolean canBeReplaced(BlockPlaceContext context, ImmutableBlockState state) { for (AbstractBlockBehavior behavior : this.behaviors) { @@ -399,4 +393,31 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior behavior.onProjectileHit(thisBlock, args, superMethod); } } + + @Override + public void placeMultiState(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + behavior.placeMultiState(thisBlock, args, superMethod); + } + } + + @Override + public boolean canPlaceMultiState(BlockAccessor accessor, BlockPos pos, ImmutableBlockState state) { + for (AbstractBlockBehavior behavior : this.behaviors) { + if (!behavior.canPlaceMultiState(accessor, pos, state)) { + return false; + } + } + return true; + } + + @Override + public boolean hasMultiState(ImmutableBlockState baseState) { + for (AbstractBlockBehavior behavior : this.behaviors) { + if (behavior.hasMultiState(baseState)) { + return true; + } + } + return false; + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/SimpleStorageBlockEntity.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/SimpleStorageBlockEntity.java index c153b554e..625818617 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/SimpleStorageBlockEntity.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/SimpleStorageBlockEntity.java @@ -175,7 +175,7 @@ public class SimpleStorageBlockEntity extends BlockEntity { if (state == null || state.behavior() != this.behavior) return; Property property = this.behavior.openProperty(); if (property == null) return; - super.world.world().setBlockAt(this.pos.x(), this.pos.y(), this.pos.z(), state.with(property, open), UpdateOption.UPDATE_ALL.flags()); + super.world.world().setBlockState(this.pos.x(), this.pos.y(), this.pos.z(), state.with(property, open), UpdateOption.UPDATE_ALL.flags()); } public void checkOpeners(Object level, Object pos, Object blockState) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java index e53c8da12..37d64bbf6 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurniture.java @@ -75,7 +75,6 @@ public class BukkitFurniture implements Furniture { this.hasExternalModel = false; } - Quaternionf conjugated = QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - this.location.getYaw()), 0).conjugate(); List packets = new ArrayList<>(); List minimizedPackets = new ArrayList<>(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java index 35ffe93a1..699fb7975 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java @@ -77,7 +77,7 @@ public class AxeItemBehavior extends ItemBehavior { } newState = newState.withProperties(behaviorOptional.get().filter(customState.propertiesNbt())); - BukkitExistingBlock clicked = (BukkitExistingBlock) context.getLevel().getBlockAt(context.getClickedPos()); + BukkitExistingBlock clicked = (BukkitExistingBlock) context.getLevel().getBlock(context.getClickedPos()); org.bukkit.entity.Player bukkitPlayer = null; if (player != null) { bukkitPlayer = ((org.bukkit.entity.Player) player.platformPlayer()); 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 f8cb7dfcb..add1679d3 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 @@ -81,7 +81,7 @@ public class BlockItemBehavior extends BlockBoundItemBehavior { CustomBlock block = optionalBlock.get(); BlockPos pos = context.getClickedPos(); int maxY = context.getLevel().worldHeight().getMaxBuildHeight() - 1; - if (context.getClickedFace() == Direction.UP && pos.y() >= maxY) { + if (context.getClickedFace() == Direction.UP && pos.y() > maxY) { if (player != null) { player.sendActionBar(Component.translatable("build.tooHigh").arguments(Component.text(maxY)).color(NamedTextColor.RED)); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/CompostableItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/CompostableItemBehavior.java index 50015c355..4b997abe1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/CompostableItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/CompostableItemBehavior.java @@ -38,7 +38,7 @@ public class CompostableItemBehavior extends ItemBehavior { @SuppressWarnings("UnstableApiUsage") @Override public InteractionResult useOnBlock(UseOnContext context) { - BukkitExistingBlock block = (BukkitExistingBlock) context.getLevel().getBlockAt(context.getClickedPos()); + BukkitExistingBlock block = (BukkitExistingBlock) context.getLevel().getBlock(context.getClickedPos()); BlockData blockData = block.block().getBlockData(); Object blockOwner = BlockStateUtils.getBlockOwner(BlockStateUtils.blockDataToBlockState(blockData)); if (blockOwner != MBlocks.COMPOSTER) return InteractionResult.PASS; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java index 7505b3cb7..b734543f3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java @@ -40,7 +40,7 @@ public class FlintAndSteelItemBehavior extends ItemBehavior { if (player == null) return InteractionResult.PASS; BlockPos clickedPos = context.getClickedPos(); - BukkitExistingBlock clicked = (BukkitExistingBlock) context.getLevel().getBlockAt(clickedPos); + BukkitExistingBlock clicked = (BukkitExistingBlock) context.getLevel().getBlock(clickedPos); Block block = clicked.block(); BlockPos firePos = clickedPos.relative(context.getClickedFace()); Direction direction = context.getHorizontalDirection(); @@ -95,7 +95,7 @@ public class FlintAndSteelItemBehavior extends ItemBehavior { } else { // 玩家觉得自定义方块不可燃,且点击了侧面,那么就要判断火源下方的方块是否可燃,如果不可燃,则补发声音 BlockPos belowFirePos = firePos.relative(Direction.DOWN); - BukkitExistingBlock belowFireBlock = (BukkitExistingBlock) context.getLevel().getBlockAt(belowFirePos); + BukkitExistingBlock belowFireBlock = (BukkitExistingBlock) context.getLevel().getBlock(belowFirePos); boolean belowCanBurn; try { Block belowBlock = belowFireBlock.block(); @@ -134,7 +134,7 @@ public class FlintAndSteelItemBehavior extends ItemBehavior { for (Direction dir : Direction.values()) { if (dir == relativeDirection) continue; BlockPos relPos = firePos.relative(dir); - BukkitExistingBlock nearByBlock = (BukkitExistingBlock) context.getLevel().getBlockAt(relPos); + BukkitExistingBlock nearByBlock = (BukkitExistingBlock) context.getLevel().getBlock(relPos); BlockData nearbyBlockData = nearByBlock.block().getBlockData(); Object nearbyBlockState = BlockStateUtils.blockDataToBlockState(nearbyBlockData); int stateID = BlockStateUtils.blockStateToId(nearbyBlockState); 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 05761ae5b..a603438b8 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,7 +12,6 @@ import net.momirealms.craftengine.core.item.behavior.ItemBehavior; 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.pack.PendingConfigSection; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Direction; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java index 01539c1b0..42b6715d9 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java @@ -449,6 +449,30 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory> enchantments(ComponentItemWrapper item) { + Object exactEnchantments = item.getComponentExact(DataComponentTypes.ENCHANTMENTS); + if (exactEnchantments == null) return Optional.empty(); + try { + return Optional.of(EnchantmentUtils.toList(exactEnchantments)); + } catch (ReflectiveOperationException e) { + this.plugin.logger().warn("Failed to get enchantments " + exactEnchantments, e); + return Optional.empty(); + } + } + + @Override + protected Optional> storedEnchantments(ComponentItemWrapper item) { + Object exactEnchantments = item.getComponentExact(DataComponentTypes.STORED_ENCHANTMENTS); + if (exactEnchantments == null) return Optional.empty(); + try { + return Optional.of(EnchantmentUtils.toList(exactEnchantments)); + } catch (ReflectiveOperationException e) { + this.plugin.logger().warn("Failed to get stored enchantments " + exactEnchantments, e); + return Optional.empty(); + } + } + @Override protected void storedEnchantments(ComponentItemWrapper item, List enchantments) { if (enchantments == null || enchantments.isEmpty()) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java index a00c683a9..9ebdcfa15 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/UniversalItemFactory.java @@ -226,6 +226,34 @@ public class UniversalItemFactory extends BukkitItemFactory { return Optional.of(new Enchantment(key, level)); } + @SuppressWarnings("DuplicatedCode") + @Override + protected Optional> enchantments(LegacyItemWrapper item) { + ListTag enchantmentTag = (ListTag) item.getNBTTag("Enchantments"); + if (enchantmentTag == null) return Optional.empty(); + List enchantments = new ArrayList<>(); + for (Tag tag : enchantmentTag) { + if (tag instanceof CompoundTag enchantTag) { + enchantments.add(new Enchantment(Key.of(enchantTag.getString("id")), enchantTag.getInt("lvl"))); + } + } + return Optional.of(enchantments); + } + + @SuppressWarnings("DuplicatedCode") + @Override + protected Optional> storedEnchantments(LegacyItemWrapper item) { + ListTag enchantmentTag = (ListTag) item.getNBTTag("StoredEnchantments"); + if (enchantmentTag == null) return Optional.empty(); + List enchantments = new ArrayList<>(); + for (Tag tag : enchantmentTag) { + if (tag instanceof CompoundTag enchantTag) { + enchantments.add(new Enchantment(Key.of(enchantTag.getString("id")), enchantTag.getInt("lvl"))); + } + } + return Optional.of(enchantments); + } + @Override protected void itemFlags(LegacyItemWrapper item, List flags) { if (flags == null || flags.isEmpty()) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java index 821492e0e..4b7aa72cc 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java @@ -56,6 +56,7 @@ public class BukkitPackManager extends AbstractPackManager implements Listener { public void onPlayerJoin(PlayerJoinEvent event) { if (Config.sendPackOnJoin() && !VersionHelper.isOrAbove1_20_2()) { Player player = BukkitAdaptors.adapt(event.getPlayer()); + // 可能有假人 if (player == null) return; this.sendResourcePack(player); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java index c51b012ff..ce298bf65 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java @@ -35,8 +35,6 @@ import net.momirealms.craftengine.core.plugin.compatibility.CompatibilityManager import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.dependency.Dependencies; import net.momirealms.craftengine.core.plugin.dependency.Dependency; -import net.momirealms.craftengine.core.plugin.gui.category.ItemBrowserManagerImpl; -import net.momirealms.craftengine.core.plugin.locale.TranslationManagerImpl; import net.momirealms.craftengine.core.plugin.logger.JavaPluginLogger; import net.momirealms.craftengine.core.plugin.logger.PluginLogger; import net.momirealms.craftengine.core.plugin.scheduler.SchedulerAdapter; @@ -56,7 +54,6 @@ import org.jspecify.annotations.Nullable; import java.io.*; import java.net.URL; import java.net.URLConnection; -import java.nio.file.Files; import java.nio.file.Path; import java.util.List; import java.util.Objects; @@ -104,17 +101,13 @@ public class BukkitCraftEngine extends CraftEngine { this.javaPlugin = javaPlugin; } - protected void setUpConfigAndLocale() { - this.config = new Config(this); - this.config.updateConfigCache(); - // 先读取语言后,再重载语言文件系统 - this.config.loadForcedLocale(); - this.translationManager = new TranslationManagerImpl(this); - this.translationManager.reload(); - // 最后才加载完整的config配置 - this.config.loadFullSettings(); + @Override + public void setUpConfigAndLocale() { + super.setUpConfigAndLocale(); + super.packManager = new BukkitPackManager(this); } + // 这个方法应该尽早被执行,最好是boostrap阶段 public void injectRegistries() { if (super.blockManager != null) return; try { @@ -129,13 +122,25 @@ public class BukkitCraftEngine extends CraftEngine { } catch (Exception e) { throw new InjectionException("Error injecting loot entries", e); } + try { + FeatureInjector.init(); + } catch (Exception e) { + throw new InjectionException("Error injecting features", e); + } + try { + BlockStateProviderInjector.init(); + } catch (Exception e) { + throw new InjectionException("Error injecting block state providers", e); + } } @Override public void onPluginLoad() { + // 普通bukkit插件会到这里才注册自定义方块 if (super.blockManager == null) { this.injectRegistries(); } + // 注入一些新的类型,但是并不需要太早 try { WorldStorageInjector.init(); } catch (Exception e) { @@ -151,12 +156,44 @@ public class BukkitCraftEngine extends CraftEngine { } catch (Exception e) { throw new InjectionException("Error initializing ProtectedFieldVisitor", e); } + // 初始化一些注册表 super.onPluginLoad(); - super.networkManager = new BukkitNetworkManager(this); - super.blockManager.init(); - super.itemManager = new BukkitItemManager(this); - this.successfullyLoaded = true; + BukkitBlockBehaviors.init(); + BukkitItemBehaviors.init(); + BukkitHitBoxTypes.init(); + BukkitBlockEntityElementConfigs.init(); + // 初始化 onload 阶段的兼容性 super.compatibilityManager().onLoad(); + // 创建网络管理器 + super.networkManager = new BukkitNetworkManager(this); + // 初始化方块管理器,获取镜像注册表,初始化网络映射 + super.blockManager.init(); + // 初始化物品管理器 + super.itemManager = new BukkitItemManager(this); + // 初始化配方管理器 + super.recipeManager = new BukkitRecipeManager(this); + // 初始化GUI管理器 + super.guiManager = new BukkitGuiManager(this); + // 初始化世界管理器 + super.worldManager = new BukkitWorldManager(this); + // 初始化声音管理器 + super.soundManager = new BukkitSoundManager(this); + // 初始化战利品管理器 + super.vanillaLootManager = new BukkitVanillaLootManager(this); + // 初始化字体管理器 + super.fontManager = new BukkitFontManager(this); + // 初始化进度管理器 + super.advancementManager = new BukkitAdvancementManager(this); + // 初始化弹射物管理器 + super.projectileManager = new BukkitProjectileManager(this); + // 初始化座椅管理器 + super.seatManager = new BukkitSeatManager(this); + // 初始化家具管理器 + super.furnitureManager = new BukkitFurnitureManager(this); + // 注册默认的parser + this.registerDefaultParsers(); + // 完成加载 + this.successfullyLoaded = true; } @Override @@ -193,39 +230,16 @@ public class BukkitCraftEngine extends CraftEngine { Bukkit.getServer().shutdown(); return; } - BukkitBlockBehaviors.init(); - BukkitItemBehaviors.init(); - BukkitHitBoxTypes.init(); - BukkitBlockEntityElementConfigs.init(); - super.packManager = new BukkitPackManager(this); + // 初始化指令发送者工厂 super.senderFactory = new BukkitSenderFactory(this); - super.recipeManager = new BukkitRecipeManager(this); + // 初始化指令管理器 super.commandManager = new BukkitCommandManager(this); - super.itemBrowserManager = new ItemBrowserManagerImpl(this); - super.guiManager = new BukkitGuiManager(this); - super.worldManager = new BukkitWorldManager(this); - super.soundManager = new BukkitSoundManager(this); - super.vanillaLootManager = new BukkitVanillaLootManager(this); - super.fontManager = new BukkitFontManager(this); - super.advancementManager = new BukkitAdvancementManager(this); - super.projectileManager = new BukkitProjectileManager(this); - super.furnitureManager = new BukkitFurnitureManager(this); - super.seatManager = new BukkitSeatManager(this); - super.onPluginEnable(); - super.compatibilityManager().onEnable(); - - // todo 未来版本移除 - Path legacyFile1 = this.dataFolderPath().resolve("additional-real-blocks.yml"); - Path legacyFile2 = this.dataFolderPath().resolve("mappings.yml"); - if (Files.exists(legacyFile1)) { - try { - Files.delete(legacyFile1); - Files.deleteIfExists(legacyFile2); - this.saveResource("resources/internal/configuration/mappings.yml"); - } catch (IOException e) { - this.logger.warn("Failed to delete legacy files", e); - } + try { + super.compatibilityManager().onEnable(); + } catch (Throwable t) { + this.logger.severe("Failed to enable compatibility manager", t); } + super.onPluginEnable(); } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockGenerator.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockGenerator.java index b757fae76..2951ddc1e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockGenerator.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockGenerator.java @@ -25,7 +25,7 @@ import net.momirealms.craftengine.core.block.BlockKeys; import net.momirealms.craftengine.core.block.BlockShape; import net.momirealms.craftengine.core.block.DelegatingBlock; import net.momirealms.craftengine.core.block.behavior.EmptyBlockBehavior; -import net.momirealms.craftengine.core.block.behavior.special.FallOnBlockBehavior; +import net.momirealms.craftengine.core.block.behavior.FallOnBlockBehavior; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.Key; @@ -175,6 +175,9 @@ public final class BlockGenerator { // onProjectileHit .method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$onProjectileHit)) .intercept(MethodDelegation.to(OnProjectileHitInterceptor.INSTANCE)) + // setPlaceBy + .method(ElementMatchers.is(CoreReflections.method$Block$setPlacedBy)) + .intercept(MethodDelegation.to(SetPlaceByInterceptor.INSTANCE)) ; // 1.21.5+ if (CoreReflections.method$BlockBehaviour$affectNeighborsAfterRemoval != null) { @@ -811,4 +814,18 @@ public final class BlockGenerator { } } } + + public static class SetPlaceByInterceptor { + public static final SetPlaceByInterceptor INSTANCE = new SetPlaceByInterceptor(); + + @RuntimeType + public void intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable superMethod) { + ObjectHolder holder = ((DelegatingBlock) thisObj).behaviorDelegate(); + try { + holder.value().placeMultiState(thisObj, args, superMethod); + } catch (Exception e) { + CraftEngine.instance().logger().severe("Failed to run setPlaceBy", e); + } + } + } } \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockStateProviderInjector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockStateProviderInjector.java new file mode 100644 index 000000000..aace908c9 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockStateProviderInjector.java @@ -0,0 +1,32 @@ +package net.momirealms.craftengine.bukkit.plugin.injector; + +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries; +import net.momirealms.craftengine.bukkit.util.KeyUtils; +import net.momirealms.craftengine.core.util.Key; + +import java.util.Set; + +public final class BlockStateProviderInjector { + + private BlockStateProviderInjector() {} + + public static void init() throws ReflectiveOperationException { + CoreReflections.field$MappedRegistry$frozen.set(MBuiltInRegistries.BLOCKSTATE_PROVIDER_TYPE, false); + + register(Key.of("craftengine:simple_state_provider"), FastNMS.INSTANCE.getCraftEngineCustomSimpleStateProviderType()); + register(Key.of("craftengine:weighted_state_provider"), FastNMS.INSTANCE.getCraftEngineCustomWeightedStateProviderType()); + register(Key.of("craftengine:rotated_block_provider"), FastNMS.INSTANCE.getCraftEngineCustomRotatedBlockProviderType()); + register(Key.of("craftengine:randomized_int_state_provider"), FastNMS.INSTANCE.getCraftEngineCustomRandomizedIntStateProviderType()); + + CoreReflections.field$MappedRegistry$frozen.set(MBuiltInRegistries.BLOCKSTATE_PROVIDER_TYPE, true); + } + + private static void register(Key id, Object type) throws ReflectiveOperationException { + Object resourceLocation = KeyUtils.toResourceLocation(id); + Object holder = CoreReflections.method$Registry$registerForHolder.invoke(null, MBuiltInRegistries.BLOCKSTATE_PROVIDER_TYPE, resourceLocation, type); + CoreReflections.method$Holder$Reference$bindValue.invoke(holder, type); + CoreReflections.field$Holder$Reference$tags.set(holder, Set.of()); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/FeatureInjector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/FeatureInjector.java new file mode 100644 index 000000000..9c7ff2cb7 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/FeatureInjector.java @@ -0,0 +1,25 @@ +package net.momirealms.craftengine.bukkit.plugin.injector; + +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries; +import net.momirealms.craftengine.bukkit.util.KeyUtils; +import net.momirealms.craftengine.core.util.Key; + +import java.util.Set; + +public final class FeatureInjector { + + private FeatureInjector() {} + + public static void init() throws ReflectiveOperationException { + Object registry = MBuiltInRegistries.FEATURE; + CoreReflections.field$MappedRegistry$frozen.set(registry, false); + Object resourceLocation = KeyUtils.toResourceLocation(Key.of("craftengine:simple_block")); + Object type = FastNMS.INSTANCE.getCraftEngineCustomSimpleBlockFeature(); + Object holder = CoreReflections.method$Registry$registerForHolder.invoke(null, registry, resourceLocation, type); + CoreReflections.method$Holder$Reference$bindValue.invoke(holder, type); + CoreReflections.field$Holder$Reference$tags.set(holder, Set.of()); + CoreReflections.field$MappedRegistry$frozen.set(registry, true); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/ProtectedFieldVisitor.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/ProtectedFieldVisitor.java index 2aa8e66c3..e53215bed 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/ProtectedFieldVisitor.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/ProtectedFieldVisitor.java @@ -18,6 +18,8 @@ import java.lang.reflect.Modifier; public final class ProtectedFieldVisitor { private static FieldAccessor internalFieldAccessor; + private ProtectedFieldVisitor() {} + public static void init() throws ReflectiveOperationException { ByteBuddy byteBuddy = new ByteBuddy(ClassFileVersion.JAVA_V17); // InternalFieldAccessor Interface diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java index 179b62e47..056cac825 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java @@ -40,6 +40,8 @@ public final class RecipeInjector { private static Class clazz$InjectedRepairItemRecipe; private static Class clazz$InjectedFireworkStarFadeRecipe; + private RecipeInjector() {} + public static void init() { ByteBuddy byteBuddy = new ByteBuddy(ClassFileVersion.JAVA_V17); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/WorldStorageInjector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/WorldStorageInjector.java index fd65f8003..0d90bceef 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/WorldStorageInjector.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/WorldStorageInjector.java @@ -43,6 +43,8 @@ public final class WorldStorageInjector { private static Class clazz$InjectedPalettedContainer; private static MethodHandle constructor$InjectedLevelChunkSection; + private WorldStorageInjector() {} + public static void init() throws ReflectiveOperationException { ByteBuddy byteBuddy = new ByteBuddy(ClassFileVersion.JAVA_V17); // Paletted Container diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java index 1ff589e57..99cf38b5f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java @@ -121,6 +121,7 @@ import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.time.Instant; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiFunction; @@ -433,6 +434,11 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes new SetObjectiveListener1_20(), this.packetIds.clientboundSetObjectivePacket(), "ClientboundSetObjectivePacket" ); + registerS2CGamePacketListener( + VersionHelper.isOrAbove1_20_3() ? + new PlayerChatListener_1_20_3() : + new PlayerChatListener_1_20(), + this.packetIds.clientboundPlayerChatPacket(), "ClientboundPlayerChatPacket"); } @EventHandler(priority = EventPriority.LOWEST) @@ -1118,7 +1124,6 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes @Override public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { BukkitServerPlayer player = (BukkitServerPlayer) user; - if (!player.isMiningBlock()) return; Object hand = FastNMS.INSTANCE.field$ServerboundSwingPacket$hand(packet); if (hand == CoreReflections.instance$InteractionHand$MAIN_HAND) { player.onSwingHand(); @@ -4206,4 +4211,193 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } } } + + public static class PlayerChatListener_1_20 implements ByteBufferPacketListener { + + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptPlayerChat()) return; + FriendlyByteBuf buf = event.getBuffer(); + boolean changed = false; + UUID sender = buf.readUUID(); + int index = buf.readVarInt(); + byte @Nullable [] messageSignature = buf.readNullable(b -> { + byte[] bs = new byte[256]; + buf.readBytes(bs); + return bs; + }); + // SignedMessageBody.Packed start + String content = buf.readUtf(256); + Instant timeStamp = buf.readInstant(); + long salt = buf.readLong(); + // LastSeenMessages.Packed start + ArrayList> lastSeen = buf.readCollection(FriendlyByteBuf.limitValue(ArrayList::new, 20), b -> { + int i = b.readVarInt() - 1; + if (i == -1) { + byte[] bs = new byte[256]; + buf.readBytes(bs); + return Pair.of(-1, bs); + } else { + return Pair.of(i, null); + } + }); + // LastSeenMessages.Packed end + // SignedMessageBody.Packed end + @Nullable String unsignedContent = buf.readNullable(FriendlyByteBuf::readUtf); + if (unsignedContent != null) { + Map unsignedContentTokens = CraftEngine.instance().fontManager().matchTags(unsignedContent); + if (!unsignedContentTokens.isEmpty()) { + Tag tag = MRegistryOps.JSON.convertTo(MRegistryOps.SPARROW_NBT, GsonHelper.get().fromJson(unsignedContent, JsonElement.class)); + Component component = AdventureHelper.nbtToComponent(tag); + component = AdventureHelper.replaceText(component, unsignedContentTokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)); + unsignedContent = MRegistryOps.SPARROW_NBT.convertTo(MRegistryOps.JSON, AdventureHelper.componentToNbt(component)).toString(); + changed = true; + } + } + // FilterMask start + int type = buf.readVarInt(); + BitSet mask = type == 2 /* PARTIALLY_FILTERED */ ? buf.readBitSet() : null; + // FilterMask end + // ChatType.BoundNetwork start + int chatType = buf.readVarInt(); + String name = buf.readUtf(); + Map nameTokens = CraftEngine.instance().fontManager().matchTags(name); + if (!nameTokens.isEmpty()) { + Tag tag = MRegistryOps.JSON.convertTo(MRegistryOps.SPARROW_NBT, GsonHelper.get().fromJson(name, JsonElement.class)); + Component component = AdventureHelper.nbtToComponent(tag); + component = AdventureHelper.replaceText(component, nameTokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)); + name = MRegistryOps.SPARROW_NBT.convertTo(MRegistryOps.JSON, AdventureHelper.componentToNbt(component)).toString(); + changed = true; + } + @Nullable String targetName = buf.readNullable(FriendlyByteBuf::readUtf); + if (targetName != null) { + Map targetNameTokens = CraftEngine.instance().fontManager().matchTags(targetName); + if (!targetNameTokens.isEmpty()) { + Tag tag = MRegistryOps.JSON.convertTo(MRegistryOps.SPARROW_NBT, GsonHelper.get().fromJson(targetName, JsonElement.class)); + Component component = AdventureHelper.nbtToComponent(tag); + component = AdventureHelper.replaceText(component, targetNameTokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)); + targetName = MRegistryOps.SPARROW_NBT.convertTo(MRegistryOps.JSON, AdventureHelper.componentToNbt(component)).toString(); + changed = true; + } + } + // ChatType.BoundNetwork end + if (changed) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUUID(sender); + buf.writeVarInt(index); + buf.writeNullable(messageSignature, (b, bs) -> buf.writeBytes(bs)); + buf.writeUtf(content); + buf.writeInstant(timeStamp); + buf.writeLong(salt); + buf.writeCollection(lastSeen, (b, pair) -> { + b.writeVarInt(pair.left() + 1); + if (pair.right() != null) { + b.writeBytes(pair.right()); + } + }); + buf.writeNullable(unsignedContent, FriendlyByteBuf::writeUtf); + buf.writeVarInt(type); + if (type == 2) buf.writeBitSet(mask); + buf.writeVarInt(chatType); + buf.writeUtf(name); + buf.writeNullable(targetName, FriendlyByteBuf::writeUtf); + } + } + } + + public static class PlayerChatListener_1_20_3 implements ByteBufferPacketListener { + + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptPlayerChat()) return; + FriendlyByteBuf buf = event.getBuffer(); + boolean changed = false; + int globalIndex = VersionHelper.isOrAbove1_21_5() ? buf.readVarInt() : -1; + UUID sender = buf.readUUID(); + int index = buf.readVarInt(); + byte @Nullable [] messageSignature = buf.readNullable(b -> { + byte[] bs = new byte[256]; + buf.readBytes(bs); + return bs; + }); + // SignedMessageBody.Packed start + String content = buf.readUtf(256); + Instant timeStamp = buf.readInstant(); + long salt = buf.readLong(); + // LastSeenMessages.Packed start + ArrayList> lastSeen = buf.readCollection(FriendlyByteBuf.limitValue(ArrayList::new, 20), b -> { + int i = b.readVarInt() - 1; + if (i == -1) { + byte[] bs = new byte[256]; + buf.readBytes(bs); + return Pair.of(-1, bs); + } else { + return Pair.of(i, null); + } + }); + // LastSeenMessages.Packed end + // SignedMessageBody.Packed end + @Nullable Tag unsignedContent = buf.readNullable(b -> b.readNbt(false)); + if (unsignedContent != null) { + Map tokens = CraftEngine.instance().fontManager().matchTags(unsignedContent); + if (!tokens.isEmpty()) { + Component component = AdventureHelper.tagToComponent(unsignedContent); + component = AdventureHelper.replaceText(component, tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)); + unsignedContent = AdventureHelper.componentToTag(component); + changed = true; + } + } + // FilterMask start + int type = buf.readVarInt(); + BitSet mask = type == 2 /* PARTIALLY_FILTERED */ ? buf.readBitSet() : null; + // FilterMask end + // ChatType.Bound start + int chatType = buf.readVarInt(); + Tag name = buf.readNbt(false); + if (name != null) { + Map tokens = CraftEngine.instance().fontManager().matchTags(name); + if (!tokens.isEmpty()) { + Component component = AdventureHelper.tagToComponent(name); + component = AdventureHelper.replaceText(component, tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)); + name = AdventureHelper.componentToTag(component); + changed = true; + } + } + @Nullable Tag targetName = buf.readNullable(b -> b.readNbt(false)); + if (targetName != null) { + Map tokens = CraftEngine.instance().fontManager().matchTags(targetName); + if (!tokens.isEmpty()) { + Component component = AdventureHelper.tagToComponent(targetName); + component = AdventureHelper.replaceText(component, tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)); + targetName = AdventureHelper.componentToTag(component); + changed = true; + } + } + // ChatType.Bound end + if (changed) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + if (VersionHelper.isOrAbove1_21_5()) buf.writeVarInt(globalIndex); + buf.writeUUID(sender); + buf.writeVarInt(index); + buf.writeNullable(messageSignature, (b, bs) -> buf.writeBytes(bs)); + buf.writeUtf(content); + buf.writeInstant(timeStamp); + buf.writeLong(salt); + buf.writeCollection(lastSeen, (b, pair) -> { + b.writeVarInt(pair.left() + 1); + if (pair.right() != null) { + b.writeBytes(pair.right()); + } + }); + buf.writeNullable(unsignedContent, (b, tag) -> b.writeNbt(tag, false)); + buf.writeVarInt(type); + if (type == 2) buf.writeBitSet(mask); + buf.writeVarInt(chatType); + buf.writeNbt(name, false); + buf.writeNullable(targetName, (b, tag) -> b.writeNbt(tag, false)); + } + } + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketIds.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketIds.java index 15a5f2b0f..67936ef29 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketIds.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketIds.java @@ -75,4 +75,6 @@ public interface PacketIds { int clientboundForgetLevelChunkPacket(); int serverboundCustomPayloadPacket(); + + int clientboundPlayerChatPacket(); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20.java index ecc7b7a1e..2245921ae 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20.java @@ -190,4 +190,9 @@ public class PacketIds1_20 implements PacketIds { public int serverboundCustomPayloadPacket() { return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ServerboundCustomPayloadPacket, PacketFlow.SERVERBOUND); } + + @Override + public int clientboundPlayerChatPacket() { + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundPlayerChatPacket, PacketFlow.CLIENTBOUND); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java index 2b6d35656..9ea4b0483 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java @@ -189,4 +189,9 @@ public class PacketIds1_20_5 implements PacketIds { public int serverboundCustomPayloadPacket() { return PlayPacketIdHelper.byName("minecraft:custom_payload", PacketFlow.SERVERBOUND); } + + @Override + public int clientboundPlayerChatPacket() { + return PlayPacketIdHelper.byName("minecraft:player_chat", PacketFlow.CLIENTBOUND); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java index 5547f8c7d..4bef1277b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java @@ -639,7 +639,6 @@ public final class CoreReflections { ), VersionHelper.isOrAbove1_21_5()); - public static final Method method$Registry$getId = requireNonNull( ReflectionUtils.getMethod(clazz$Registry, int.class, Object.class) ); @@ -4485,6 +4484,10 @@ public final class CoreReflections { ReflectionUtils.getDeclaredField(clazz$EnumProperty, VersionHelper.isOrAbove1_21_2() ? List.class : ImmutableSet.class, 0) ); + public static final Method method$Block$setPlacedBy = requireNonNull( + ReflectionUtils.getMethod(clazz$Block, void.class, clazz$Level, clazz$BlockPos, clazz$BlockState, clazz$LivingEntity, clazz$ItemStack) + ); + public static final Class clazz$ItemCost = MiscUtils.requireNonNullIf( BukkitReflectionUtils.findReobfOrMojmapClass( "world.item.trading.ItemCost", @@ -4548,4 +4551,25 @@ public final class CoreReflections { public static final Field field$ChunkMap$chunkGenerator = MiscUtils.requireNonNullIf( ReflectionUtils.getDeclaredField(clazz$ChunkMap, clazz$ChunkGenerator, 0), !VersionHelper.isOrAbove1_20_5() ); + + public static final Class clazz$BlockStateProvider = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.level.levelgen.feature.stateproviders.WorldGenFeatureStateProvider", + "world.level.levelgen.feature.stateproviders.BlockStateProvider" + ) + ); + + public static final Class clazz$BlockStateProviderType = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.level.levelgen.feature.stateproviders.WorldGenFeatureStateProviders", + "world.level.levelgen.feature.stateproviders.BlockStateProviderType" + ) + ); + + public static final Class clazz$Feature = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.level.levelgen.feature.WorldGenerator", + "world.level.levelgen.feature.Feature" + ) + ); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBuiltInRegistries.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBuiltInRegistries.java index b73fe0d00..a5f47d97f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBuiltInRegistries.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBuiltInRegistries.java @@ -26,6 +26,8 @@ public final class MBuiltInRegistries { public static final Object DATA_COMPONENT_PREDICATE_TYPE; public static final Object LOOT_POOL_ENTRY_TYPE; public static final Object GAME_EVENT; + public static final Object BLOCKSTATE_PROVIDER_TYPE; + public static final Object FEATURE; static { Field[] fields = CoreReflections.clazz$BuiltInRegistries.getDeclaredFields(); @@ -44,6 +46,8 @@ public final class MBuiltInRegistries { Object registries$DataComponentPredicateType = null; Object registries$LootPoolEntryType = null; Object registries$GameEvent = null; + Object registries$BlockStateProviderType = null; + Object registries$Feature = null; for (Field field : fields) { Type fieldType = field.getGenericType(); @@ -59,6 +63,10 @@ public final class MBuiltInRegistries { registries$RecipeType = field.get(null); } else if (rawType == CoreReflections.clazz$BlockEntityType) { registries$BlockEntityType = field.get(null); + } else if (rawType == CoreReflections.clazz$BlockStateProviderType) { + registries$BlockStateProviderType = field.get(null); + } else if (rawType == CoreReflections.clazz$Feature) { + registries$Feature = field.get(null); } else if (VersionHelper.isOrAbove1_20_5() && rawType == CoreReflections.clazz$DataComponentType && registries$DataComponentType == null) { registries$DataComponentType = field.get(null); } else if (VersionHelper.isOrAbove1_21_5() && rawType == CoreReflections.clazz$DataComponentPredicate$Type) { @@ -98,6 +106,8 @@ public final class MBuiltInRegistries { LOOT_POOL_ENTRY_TYPE = requireNonNull(registries$LootPoolEntryType); DATA_COMPONENT_TYPE = registries$DataComponentType; GAME_EVENT = requireNonNull(registries$GameEvent); + BLOCKSTATE_PROVIDER_TYPE = requireNonNull(registries$BlockStateProviderType); + FEATURE = requireNonNull(registries$Feature); DATA_COMPONENT_PREDICATE_TYPE = registries$DataComponentPredicateType; } catch (ReflectiveOperationException e) { throw new ReflectionInitException("Failed to init BuiltInRegistries", e); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MTagKeys.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MTagKeys.java index 3f444599e..fb818baa7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MTagKeys.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MTagKeys.java @@ -7,12 +7,14 @@ import java.util.Objects; public final class MTagKeys { private MTagKeys() {} + public static final Object Fluid$WATER = create(MRegistries.FLUID, "water"); public static final Object Item$WOOL = create(MRegistries.ITEM, "wool"); public static final Object Block$WALLS = create(MRegistries.BLOCK, "walls"); public static final Object Block$SHULKER_BOXES = create(MRegistries.BLOCK, "shulker_boxes"); public static final Object Block$FENCES = create(MRegistries.BLOCK, "fences"); public static final Object Block$WOODEN_FENCES = create(MRegistries.BLOCK, "wooden_fences"); public static final Object Block$DIRT = create(MRegistries.BLOCK, "dirt"); + public static final Object Block$SNOW = create(MRegistries.BLOCK, "snow"); private static Object create(Object registry, String location) { Object resourceLocation = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", location); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java index f5b1e4ee9..a8f62e3ac 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/NetworkReflections.java @@ -1726,4 +1726,10 @@ public final class NetworkReflections { clazz$ClientboundUpdateTagsPacket, Map.class, 0 ) ); + + public static final Class clazz$ClientboundPlayerChatPacket = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("network.protocol.game.ClientboundPlayerChatPacket") + ) + ); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java index 7137b22a5..3487d233f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java @@ -104,6 +104,7 @@ public class BukkitServerPlayer extends Player { private boolean isDestroyingBlock; private boolean isDestroyingCustomBlock; private boolean swingHandAck; + private int lastSwingHandTick; private float miningProgress; // for client visual sync private int resentSoundTick; @@ -131,6 +132,12 @@ public class BukkitServerPlayer extends Player { // selected client locale @Nullable private Locale selectedLocale; + // 存储客户端在发送停止破坏包前正在破坏的最后一个方块 + private BlockPos lastStopMiningPos; + // 修复连续挖掘的标志位 + private boolean isHackedBreak; + // 上一次停止挖掘包发出的时间 + private int lastStopMiningTick; public BukkitServerPlayer(BukkitCraftEngine plugin, @Nullable Channel channel) { this.channel = channel; @@ -518,8 +525,33 @@ public class BukkitServerPlayer extends Player { if (this.gameTicks % 20 == 0) { this.updateGUI(); } - if (this.isDestroyingBlock) { - this.tickBlockDestroy(); + if (hasSwingHand()) { + if (this.isDestroyingBlock) { + this.tickBlockDestroy(); + } else if (this.lastStopMiningPos != null && this.gameTicks - this.lastStopMiningTick <= 5) { + double range = getCachedInteractionRange(); + RayTraceResult result = platformPlayer().rayTraceBlocks(range, FluidCollisionMode.NEVER); + if (result != null) { + Block hitBlock = result.getHitBlock(); + if (hitBlock != null) { + Location location = hitBlock.getLocation(); + BlockPos hitPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + if (hitPos.equals(this.lastStopMiningPos)) { + Object blockState = BlockStateUtils.getBlockState(hitBlock); + this.startMiningBlock(hitPos, blockState, BlockStateUtils.getOptionalCustomBlockState(blockState).orElse(null)); + this.lastStopMiningPos = null; + this.lastStopMiningTick = 0; + this.isHackedBreak = true; + } + } + } + } + this.swingHandAck = false; + } else { + if (this.isHackedBreak) { + this.abortMiningBlock(); + this.isHackedBreak = false; + } } if (Config.predictBreaking() && !this.isDestroyingCustomBlock) { // if it's not destroying blocks, we do predict @@ -607,6 +639,10 @@ public class BukkitServerPlayer extends Player { } public void startMiningBlock(BlockPos pos, Object state, @Nullable ImmutableBlockState immutableBlockState) { + if (this.isHackedBreak) { + this.isHackedBreak = false; + this.abortMiningBlock(); + } // instant break boolean custom = immutableBlockState != null; if (custom && getDestroyProgress(state, pos) >= 1f) { @@ -668,8 +704,11 @@ public class BukkitServerPlayer extends Player { } } + // 客户端觉得要停止破坏方块了 @Override public void stopMiningBlock() { + this.lastStopMiningPos = this.destroyPos; + this.lastStopMiningTick = gameTicks(); setClientSideCanBreakBlock(true); setIsDestroyingBlock(false, false); } @@ -705,8 +744,6 @@ public class BukkitServerPlayer extends Player { private void tickBlockDestroy() { // if player swings hand is this tick - if (!this.swingHandAck) return; - this.swingHandAck = false; int currentTick = gameTicks(); // optimize break speed, otherwise it would be too fast if (currentTick - this.lastSuccessfulBreak <= 5) return; @@ -863,6 +900,11 @@ public class BukkitServerPlayer extends Player { @Override public void onSwingHand() { this.swingHandAck = true; + this.lastSwingHandTick = gameTicks(); + } + + public boolean hasSwingHand() { + return this.swingHandAck && this.lastSwingHandTick + 2 > gameTicks(); } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EnchantmentUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EnchantmentUtils.java index 2a6bd2117..4acfccf36 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EnchantmentUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EnchantmentUtils.java @@ -1,20 +1,37 @@ package net.momirealms.craftengine.bukkit.util; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +import net.momirealms.craftengine.core.item.data.Enchantment; +import net.momirealms.craftengine.core.util.Key; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; public final class EnchantmentUtils { private EnchantmentUtils() {} + @SuppressWarnings("unchecked") + public static List toList(Object itemEnchantments) throws ReflectiveOperationException { + if (itemEnchantments == null) return List.of(); + List enchantmentList = new ArrayList<>(); + Map enchantments = (Map) CoreReflections.field$ItemEnchantments$enchantments.get(itemEnchantments); + for (Map.Entry entry : enchantments.entrySet()) { + Object holder = entry.getKey(); + String name = (String) CoreReflections.method$Holder$getRegisteredName.invoke(holder); + int level = entry.getValue(); + enchantmentList.add(new Enchantment(Key.of(name), level)); + } + return enchantmentList; + } + @SuppressWarnings("unchecked") public static Map toMap(Object itemEnchantments) throws ReflectiveOperationException { if (itemEnchantments == null) return Map.of(); Map map = new HashMap<>(); Map enchantments = (Map) CoreReflections.field$ItemEnchantments$enchantments.get(itemEnchantments); - for (Map.Entry entry : enchantments.entrySet()) { Object holder = entry.getKey(); String name = (String) CoreReflections.method$Holder$getRegisteredName.invoke(holder); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java index 4a3b36f80..66df48ee3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java @@ -57,7 +57,13 @@ public class BukkitWorld implements World { } @Override - public ExistingBlock getBlockAt(int x, int y, int z) { + public BlockStateWrapper getBlockState(int x, int y, int z) { + Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(this.serverWorld(), LocationUtils.toBlockPos(x, y, z)); + return BlockStateUtils.toBlockStateWrapper(blockState); + } + + @Override + public ExistingBlock getBlock(int x, int y, int z) { return new BukkitExistingBlock(platformWorld().getBlockAt(x, y, z)); } @@ -120,7 +126,7 @@ public class BukkitWorld implements World { } @Override - public void setBlockAt(int x, int y, int z, BlockStateWrapper blockState, int flags) { + public void setBlockState(int x, int y, int z, BlockStateWrapper blockState, int flags) { Object worldServer = serverWorld(); Object blockPos = FastNMS.INSTANCE.constructor$BlockPos(x, y, z); FastNMS.INSTANCE.method$LevelWriter$setBlock(worldServer, blockPos, blockState.literalObject(), flags); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java index ba41c8181..082ae0d6c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java @@ -49,9 +49,6 @@ public class BukkitWorldManager implements WorldManager, Listener { this.plugin = plugin; this.worlds = ConcurrentUUID2ReferenceChainedHashTable.createWithCapacity(10, 0.5f); this.storageAdaptor = new DefaultStorageAdaptor(); - for (World world : Bukkit.getWorlds()) { - this.worlds.put(world.getUID(), new BukkitCEWorld(new BukkitWorld(world), this.storageAdaptor)); - } } @Override @@ -76,6 +73,11 @@ public class BukkitWorldManager implements WorldManager, Listener { if (world != null) { this.lastWorldUUID = uuid; this.lastWorld = world; + } else { + World bukkitWorld = Bukkit.getWorld(uuid); + if (bukkitWorld != null) { + world = this.loadWorld(new BukkitWorld(bukkitWorld)); + } } return world; } @@ -90,7 +92,7 @@ public class BukkitWorldManager implements WorldManager, Listener { } public void delayedInit() { - // load loaded chunks + // 此时大概率为空,暂且保留代码 for (World world : Bukkit.getWorlds()) { BukkitWorld wrappedWorld = new BukkitWorld(world); try { @@ -132,15 +134,38 @@ public class BukkitWorldManager implements WorldManager, Listener { this.lastWorldUUID = null; } + @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) + public void onWorldInit(WorldInitEvent event) { + World world = event.getWorld(); + UUID uuid = world.getUID(); + if (this.worlds.containsKey(uuid)) return; + CEWorld ceWorld = new BukkitCEWorld(new BukkitWorld(world), this.storageAdaptor); + this.worlds.put(uuid, ceWorld); + this.resetWorldArray(); + this.injectChunkGenerator(ceWorld); + } + @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onWorldLoad(WorldLoadEvent event) { - this.loadWorld(new BukkitWorld(event.getWorld())); + World world = event.getWorld(); + UUID uuid = world.getUID(); + if (this.worlds.containsKey(uuid)) { + CEWorld ceWorld = this.worlds.get(uuid); + for (Chunk chunk : world.getLoadedChunks()) { + handleChunkLoad(ceWorld, chunk, true); + } + ceWorld.setTicking(true); + } else { + this.loadWorld(new BukkitWorld(world)); + } } @Override - public void loadWorld(net.momirealms.craftengine.core.world.World world) { + public CEWorld loadWorld(net.momirealms.craftengine.core.world.World world) { UUID uuid = world.uuid(); - if (this.worlds.containsKey(uuid)) return; + if (this.worlds.containsKey(uuid)) { + return this.worlds.get(uuid); + } CEWorld ceWorld = new BukkitCEWorld(world, this.storageAdaptor); this.worlds.put(uuid, ceWorld); this.resetWorldArray(); @@ -149,6 +174,7 @@ public class BukkitWorldManager implements WorldManager, Listener { handleChunkLoad(ceWorld, chunk, false); } ceWorld.setTicking(true); + return ceWorld; } @Override diff --git a/client-mod b/client-mod new file mode 160000 index 000000000..5d958f3b4 --- /dev/null +++ b/client-mod @@ -0,0 +1 @@ +Subproject commit 5d958f3b4a3d4e4870d416f55bf3555be96020bd diff --git a/common-files/src/main/resources/config.yml b/common-files/src/main/resources/config.yml index c818e6167..139001e20 100644 --- a/common-files/src/main/resources/config.yml +++ b/common-files/src/main/resources/config.yml @@ -8,6 +8,9 @@ update-checker: true forced-locale: '' # Filter configuration phase player disconnection logs filter-configuration-phase-disconnect: false +# This option delays CraftEngine's config reading until after all plugins start. +# Don't disable this setting unless you need datapack-generated spawn chunks. +delay-configuration-load: true resource-pack: # This option determines the location of the generated resource pack @@ -99,7 +102,7 @@ resource-pack: fix-atlas: true # Optimize your resource pack by reducing its size without any quality loss. optimization: - enable: true + enable: false # .png texture: enable: true @@ -403,6 +406,7 @@ network: text-display: true # Modern Holograms item: true advancement: true + player-chat: true recipe: # Master switch for custom recipes diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/amethyst_torch.yml b/common-files/src/main/resources/resources/default/configuration/blocks/amethyst_torch.yml index 5abdab95c..a30d8cbac 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/amethyst_torch.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/amethyst_torch.yml @@ -1,15 +1,8 @@ items: default:amethyst_torch: - material: nether_brick data: item-name: - model: - type: minecraft:model - path: minecraft:item/custom/amethyst_torch - generation: - parent: minecraft:item/generated - textures: - layer0: minecraft:block/custom/amethyst_torch + texture: minecraft:block/custom/amethyst_torch behavior: - type: wall_block_item block: default:amethyst_wall_torch @@ -18,7 +11,6 @@ items: - type: block_item block: default:amethyst_wall_torch default:amethyst_standing_torch: - material: nether_brick data: item-name: model: @@ -29,7 +21,6 @@ items: textures: torch: minecraft:block/custom/amethyst_torch default:amethyst_wall_torch: - material: nether_brick data: item-name: model: diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/chessboard_block.yml b/common-files/src/main/resources/resources/default/configuration/blocks/chessboard_block.yml index cb6bfdb18..5176765db 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/chessboard_block.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/chessboard_block.yml @@ -3,11 +3,7 @@ items: material: nether_brick data: item-name: - model: - type: minecraft:model - path: minecraft:item/custom/chessboard_block - generation: - parent: minecraft:block/custom/chessboard_block + model: minecraft:block/custom/chessboard_block behavior: type: block_item block: diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/chinese_lantern.yml b/common-files/src/main/resources/resources/default/configuration/blocks/chinese_lantern.yml index 1dadb3500..78a90a395 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/chinese_lantern.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/chinese_lantern.yml @@ -3,11 +3,7 @@ items: material: nether_brick data: item-name: - model: - type: minecraft:model - path: minecraft:item/custom/chinese_lantern - generation: - parent: minecraft:block/custom/chinese_lantern + model: minecraft:block/custom/chinese_lantern behavior: type: block_item block: diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/copper_coil.yml b/common-files/src/main/resources/resources/default/configuration/blocks/copper_coil.yml index 7615f1fb6..2697254d2 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/copper_coil.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/copper_coil.yml @@ -3,11 +3,7 @@ items: material: nether_brick data: item-name: - model: - type: minecraft:model - path: minecraft:item/custom/copper_coil - generation: - parent: minecraft:block/custom/copper_coil + model: minecraft:block/custom/copper_coil behavior: type: block_item block: @@ -16,7 +12,6 @@ items: settings: template: - default:sound/metal - - default:pickaxe_power/level_1 overrides: hardness: 3.0 resistance: 4.5 @@ -27,6 +22,8 @@ items: map-color: 15 tags: - minecraft:mineable/pickaxe + correct-tools: + template: default:pickaxe_power/level_1 behavior: type: lamp_block states: diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/ender_pearl_flower.yml b/common-files/src/main/resources/resources/default/configuration/blocks/ender_pearl_flower.yml index 258f99c92..2d5b218de 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/ender_pearl_flower.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/ender_pearl_flower.yml @@ -3,10 +3,7 @@ items: material: nether_brick data: item-name: - model: - template: default:model/simplified_generated - arguments: - path: minecraft:item/custom/ender_pearl_flower_seeds + texture: minecraft:item/custom/ender_pearl_flower_seeds behavior: type: block_item block: default:ender_pearl_flower diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/fairy_flower.yml b/common-files/src/main/resources/resources/default/configuration/blocks/fairy_flower.yml index 08debd5e8..99c970515 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/fairy_flower.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/fairy_flower.yml @@ -3,10 +3,7 @@ items: material: nether_brick data: item-name: - model: - template: default:model/simplified_generated - arguments: - path: minecraft:item/custom/fairy_flower + texture: minecraft:item/custom/fairy_flower behavior: type: block_item block: diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/flame_cane.yml b/common-files/src/main/resources/resources/default/configuration/blocks/flame_cane.yml index dd50822f0..8b1e352ae 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/flame_cane.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/flame_cane.yml @@ -3,10 +3,7 @@ items: material: nether_brick data: item-name: - model: - template: default:model/simplified_generated - arguments: - path: minecraft:item/custom/flame_cane + texture: minecraft:item/custom/flame_cane behavior: type: block_item block: diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/gunpowder_block.yml b/common-files/src/main/resources/resources/default/configuration/blocks/gunpowder_block.yml index 17bf82ce5..0f55e56b9 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/gunpowder_block.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/gunpowder_block.yml @@ -3,11 +3,7 @@ items: material: nether_brick data: item-name: - model: - type: minecraft:model - path: minecraft:item/custom/gunpowder_block - generation: - parent: minecraft:block/custom/gunpowder_block + model: minecraft:block/custom/gunpowder_block behavior: type: block_item block: @@ -51,13 +47,14 @@ items: settings: template: - default:sound/stone - - default:pickaxe_power/level_1 - default:settings/solid_1x1x1 overrides: hardness: 1.8 resistance: 1.8 instrument: basedrum map-color: 45 + correct-tools: + template: default:pickaxe_power/level_1 state: auto-state: solid model: diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/hami_melon.yml b/common-files/src/main/resources/resources/default/configuration/blocks/hami_melon.yml index 67de31a05..d4e657c49 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/hami_melon.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/hami_melon.yml @@ -1,6 +1,7 @@ items: default:hami_melon_slice: material: melon_slice + texture: minecraft:item/custom/hami_melon_slice data: item-name: $$>=1.20.5: @@ -13,18 +14,11 @@ items: food: nutrition: 2 saturation: 1.0 - model: - template: default:model/simplified_generated - arguments: - path: minecraft:item/custom/hami_melon_slice default:hami_melon: material: nether_brick data: item-name: - model: - path: minecraft:item/custom/hami_melon - generation: - parent: minecraft:block/custom/hami_melon + model: minecraft:block/custom/hami_melon behavior: type: block_item block: default:hami_melon @@ -32,10 +26,7 @@ items: material: nether_brick data: item-name: - model: - template: default:model/simplified_generated - arguments: - path: minecraft:item/custom/hami_melon_seeds + texture: minecraft:item/custom/hami_melon_seeds behavior: type: block_item block: default:hami_melon_stem diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/magma_plant.yml b/common-files/src/main/resources/resources/default/configuration/blocks/magma_plant.yml index b608b57b9..7e5ed5a14 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/magma_plant.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/magma_plant.yml @@ -1,10 +1,7 @@ items: default:magma_fruit: material: carrot - model: - template: default:model/simplified_generated - arguments: - path: minecraft:item/custom/magma_fruit + texture: minecraft:item/custom/magma_fruit data: item-name: $$>=1.20.5: diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/netherite_anvil.yml b/common-files/src/main/resources/resources/default/configuration/blocks/netherite_anvil.yml index 86fbecd35..5e8e68c3e 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/netherite_anvil.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/netherite_anvil.yml @@ -1,13 +1,8 @@ items: default:netherite_anvil: - material: nether_brick data: item-name: - model: - type: minecraft:model - path: minecraft:item/custom/netherite_anvil - generation: - parent: minecraft:block/custom/netherite_anvil + model: minecraft:block/custom/netherite_anvil behavior: type: block_item block: @@ -30,21 +25,19 @@ items: - type: expression expression: '!' settings: - template: - - default:pickaxe_power/level_4 - overrides: - tags: - - minecraft:mineable/pickaxe - sounds: - break: minecraft:block.anvil.break - step: minecraft:block.anvil.step - place: minecraft:block.anvil.place - hit: minecraft:block.anvil.hit - fall: minecraft:block.anvil.fall - map-color: 29 - hardness: 10.0 - resistance: 1200 - push-reaction: block + sounds: + break: minecraft:block.anvil.break + step: minecraft:block.anvil.step + place: minecraft:block.anvil.place + hit: minecraft:block.anvil.hit + fall: minecraft:block.anvil.fall + map-color: 29 + hardness: 10.0 + resistance: 1200 + push-reaction: block + correct-tools: + template: default:pickaxe_power/level_4 + tags: ["minecraft:mineable/pickaxe"] states: properties: facing_clockwise: diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml b/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml index b3835f599..7fdbbe403 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml @@ -9,11 +9,7 @@ items: - minecraft:logs_that_burn data: item-name: - model: - type: minecraft:model - path: minecraft:item/custom/palm_log - generation: - parent: minecraft:block/custom/palm_log + model: minecraft:block/custom/palm_log behavior: type: block_item block: @@ -41,11 +37,7 @@ items: - minecraft:logs_that_burn data: item-name: - model: - type: minecraft:model - path: minecraft:item/custom/stripped_palm_log - generation: - parent: minecraft:block/custom/stripped_palm_log + model: minecraft:block/custom/stripped_palm_log behavior: type: block_item block: @@ -70,11 +62,7 @@ items: - minecraft:logs_that_burn data: item-name: - model: - type: minecraft:model - path: minecraft:item/custom/palm_wood - generation: - parent: minecraft:block/custom/palm_wood + model: minecraft:block/custom/palm_wood behavior: type: block_item block: @@ -102,11 +90,7 @@ items: - minecraft:logs_that_burn data: item-name: - model: - type: minecraft:model - path: minecraft:item/custom/stripped_palm_wood - generation: - parent: minecraft:block/custom/stripped_palm_wood + model: minecraft:block/custom/stripped_palm_wood behavior: type: block_item block: @@ -130,11 +114,7 @@ items: - minecraft:wooden_tool_materials data: item-name: - model: - type: minecraft:model - path: minecraft:item/custom/palm_planks - generation: - parent: minecraft:block/custom/palm_planks + model: minecraft:block/custom/palm_planks behavior: type: block_item block: @@ -157,11 +137,7 @@ items: lore: - "Requires the datapack tree configuration to function." - "If not configured, an oak tree will grow by default." - model: - template: default:model/generated - arguments: - model: minecraft:item/custom/palm_sapling - texture: minecraft:block/custom/palm_sapling + texture: minecraft:block/custom/palm_sapling behavior: type: block_item block: @@ -230,11 +206,7 @@ items: item-name: settings: fuel-time: 300 - model: - type: minecraft:model - path: minecraft:item/custom/palm_trapdoor - generation: - parent: minecraft:block/custom/palm_trapdoor_bottom + model: minecraft:block/custom/palm_trapdoor_bottom behavior: type: block_item block: @@ -284,10 +256,7 @@ items: item-name: settings: fuel-time: 200 - model: - template: default:model/simplified_generated - arguments: - path: minecraft:item/custom/palm_door + texture: minecraft:item/custom/palm_door behavior: type: double_high_block_item block: @@ -358,11 +327,7 @@ items: item-name: settings: fuel-time: 300 - model: - type: minecraft:model - path: minecraft:item/custom/palm_fence_gate - generation: - parent: minecraft:block/custom/palm_fence_gate + model: minecraft:block/custom/palm_fence_gate behavior: type: block_item block: @@ -414,11 +379,7 @@ items: item-name: settings: fuel-time: 150 - model: - type: minecraft:model - path: minecraft:item/custom/palm_slab - generation: - parent: minecraft:block/custom/palm_slab + model: minecraft:block/custom/palm_slab behavior: type: block_item block: @@ -456,11 +417,7 @@ items: model_double_path: minecraft:block/custom/palm_planks default:palm_stairs: material: nether_brick - model: - type: minecraft:model - path: minecraft:item/custom/palm_stairs - generation: - parent: minecraft:block/custom/palm_stairs + model: minecraft:block/custom/palm_stairs data: item-name: settings: @@ -505,11 +462,7 @@ items: textures: *textures default:palm_pressure_plate: material: nether_brick - model: - type: minecraft:model - path: minecraft:item/custom/palm_pressure_plate - generation: - parent: minecraft:block/custom/palm_pressure_plate + model: minecraft:block/custom/palm_pressure_plate data: item-name: settings: @@ -693,15 +646,15 @@ recipes: default:palm_planks: template: default:recipe/planks arguments: - wood_type: palm + wood_type: default:palm default:palm_wood: template: default:recipe/log_2_wood arguments: - wood_type: palm + wood_type: default:palm default:stripped_palm_wood: template: default:recipe/log_2_wood arguments: - wood_type: stripped_palm + wood_type: default:stripped_palm default:palm_trapdoor: type: shaped pattern: diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/pebble.yml b/common-files/src/main/resources/resources/default/configuration/blocks/pebble.yml index d9dd1ef1f..9d6c631aa 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/pebble.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/pebble.yml @@ -3,10 +3,7 @@ items: material: nether_brick data: item-name: - model: - template: default:model/simplified_generated - arguments: - path: minecraft:item/custom/pebble + texture: minecraft:item/custom/pebble behavior: - type: block_item block: diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/reed.yml b/common-files/src/main/resources/resources/default/configuration/blocks/reed.yml index 49ce9b22d..0fab82454 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/reed.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/reed.yml @@ -3,10 +3,7 @@ items: material: nether_brick data: item-name: - model: - template: default:model/simplified_generated - arguments: - path: minecraft:item/custom/reed + texture: minecraft:item/custom/reed behavior: type: liquid_collision_block_item block: diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/safe_block.yml b/common-files/src/main/resources/resources/default/configuration/blocks/safe_block.yml index 103c0a95c..21514d055 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/safe_block.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/safe_block.yml @@ -3,11 +3,7 @@ items: material: nether_brick data: item-name: - model: - type: minecraft:model - path: minecraft:item/custom/safe_block - generation: - parent: minecraft:block/custom/safe_block + model: minecraft:block/custom/safe_block behavior: type: block_item block: diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/sofa.yml b/common-files/src/main/resources/resources/default/configuration/blocks/sofa.yml index bd5e72fd3..5aba431e7 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/sofa.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/sofa.yml @@ -3,9 +3,7 @@ items: material: nether_brick data: item-name: - model: - type: minecraft:model - path: minecraft:item/custom/sleeper_sofa + model: minecraft:item/custom/sleeper_sofa behavior: type: block_item block: @@ -44,9 +42,7 @@ items: item: default:sleeper_sofa default:sofa_inner: material: nether_brick - model: - type: minecraft:model - path: minecraft:item/custom/sofa_inner + model: minecraft:item/custom/sofa_inner default:sofa: material: nether_brick data: diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/table_lamp.yml b/common-files/src/main/resources/resources/default/configuration/blocks/table_lamp.yml index adb60844a..6623e00b7 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/table_lamp.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/table_lamp.yml @@ -3,9 +3,7 @@ items: material: nether_brick data: item-name: - model: - type: minecraft:model - path: minecraft:item/custom/table_lamp + model: minecraft:item/custom/table_lamp behavior: type: block_item block: diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/topaz_ore.yml b/common-files/src/main/resources/resources/default/configuration/blocks/topaz_ore.yml index 00d5621a5..1a5a03297 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/topaz_ore.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/topaz_ore.yml @@ -3,11 +3,7 @@ items: material: nether_brick data: item-name: - model: - type: minecraft:model - path: minecraft:item/custom/topaz_ore - generation: - parent: minecraft:block/custom/topaz_ore + model: minecraft:block/custom/topaz_ore behavior: type: block_item block: default:topaz_ore @@ -15,11 +11,7 @@ items: material: nether_brick data: item-name: - model: - type: minecraft:model - path: minecraft:item/custom/deepslate_topaz_ore - generation: - parent: minecraft:block/custom/deepslate_topaz_ore + model: minecraft:block/custom/deepslate_topaz_ore behavior: type: block_item block: default:deepslate_topaz_ore @@ -32,10 +24,7 @@ items: percent: 0.25 data: item-name: <#FF8C00> - model: - template: default:model/simplified_generated - arguments: - path: minecraft:item/custom/topaz + texture: minecraft:item/custom/topaz blocks: default:topaz_ore: loot: @@ -75,26 +64,42 @@ blocks: path: minecraft:block/custom/deepslate_topaz_ore recipes: default:topaz_from_smelting_topaz_ore: - template: default:recipe/smelting_ore - arguments: - exp: 1.0 - ingredient: default:topaz_ore - result: default:topaz + type: smelting + experience: 1.0 + category: misc + group: topaz + time: 200 + ingredient: default:topaz_ore + result: + id: default:topaz + count: 1 default:topaz_from_smelting_deepslate_topaz_ore: - template: default:recipe/smelting_ore - arguments: - exp: 1.0 - ingredient: default:deepslate_topaz_ore - result: default:topaz + type: smelting + experience: 1.0 + category: misc + group: topaz + time: 200 + ingredient: default:deepslate_topaz_ore + result: + id: default:topaz + count: 1 default:topaz_from_blasting_topaz_ore: - template: default:recipe/blasting_ore - arguments: - exp: 1.0 - ingredient: default:topaz_ore - result: default:topaz + type: blasting + experience: 1.0 + category: misc + group: topaz + time: 100 + ingredient: default:topaz_ore + result: + id: default:topaz + count: 1 default:topaz_from_blasting_deepslate_topaz_ore: - template: default:recipe/blasting_ore - arguments: - exp: 1.0 - ingredient: default:deepslate_topaz_ore - result: default:topaz \ No newline at end of file + type: blasting + experience: 1.0 + category: misc + group: topaz + time: 100 + ingredient: default:deepslate_topaz_ore + result: + id: default:topaz + count: 1 \ No newline at end of file diff --git a/common-files/src/main/resources/resources/default/configuration/emoji.yml b/common-files/src/main/resources/resources/default/configuration/emoji.yml index aa001996e..4fe4b0e69 100644 --- a/common-files/src/main/resources/resources/default/configuration/emoji.yml +++ b/common-files/src/main/resources/resources/default/configuration/emoji.yml @@ -1,6 +1,6 @@ templates: default:emoji/basic: - content: '> + content: '> emoji: default:emoji_smiley: template: default:emoji/basic diff --git a/common-files/src/main/resources/resources/default/configuration/furniture/bench.yml b/common-files/src/main/resources/resources/default/configuration/furniture/bench.yml index 3b4b68471..be22a435c 100644 --- a/common-files/src/main/resources/resources/default/configuration/furniture/bench.yml +++ b/common-files/src/main/resources/resources/default/configuration/furniture/bench.yml @@ -3,9 +3,7 @@ items: material: nether_brick data: item-name: - model: - type: minecraft:model - path: minecraft:item/custom/bench + model: minecraft:item/custom/bench behavior: type: furniture_item furniture: diff --git a/common-files/src/main/resources/resources/default/configuration/furniture/flower_basket.yml b/common-files/src/main/resources/resources/default/configuration/furniture/flower_basket.yml index 0dd2ac5c2..15194da75 100644 --- a/common-files/src/main/resources/resources/default/configuration/furniture/flower_basket.yml +++ b/common-files/src/main/resources/resources/default/configuration/furniture/flower_basket.yml @@ -3,28 +3,19 @@ items: material: nether_brick data: item-name: - model: - template: default:model/simplified_generated - arguments: - path: minecraft:item/custom/flower_basket_2d + texture: minecraft:item/custom/flower_basket_2d behavior: type: furniture_item furniture: default:flower_basket default:flower_basket_ground: material: nether_brick - model: - type: minecraft:model - path: minecraft:item/custom/flower_basket_ground + model: minecraft:item/custom/flower_basket_ground default:flower_basket_wall: material: nether_brick - model: - type: minecraft:model - path: minecraft:item/custom/flower_basket_wall + model: minecraft:item/custom/flower_basket_wall default:flower_basket_ceiling: material: nether_brick - model: - type: minecraft:model - path: minecraft:item/custom/flower_basket_ceiling + model: minecraft:item/custom/flower_basket_ceiling furniture: default:flower_basket: settings: diff --git a/common-files/src/main/resources/resources/default/configuration/furniture/wooden_chair.yml b/common-files/src/main/resources/resources/default/configuration/furniture/wooden_chair.yml index 24471cfb1..9ea08846d 100644 --- a/common-files/src/main/resources/resources/default/configuration/furniture/wooden_chair.yml +++ b/common-files/src/main/resources/resources/default/configuration/furniture/wooden_chair.yml @@ -3,9 +3,7 @@ items: material: nether_brick data: item-name: - model: - type: minecraft:model - path: minecraft:item/custom/wooden_chair + model: minecraft:item/custom/wooden_chair behavior: type: furniture_item furniture: diff --git a/common-files/src/main/resources/resources/default/configuration/items/flame_elytra.yml b/common-files/src/main/resources/resources/default/configuration/items/flame_elytra.yml index e89cc0f4e..0fc952c5d 100644 --- a/common-files/src/main/resources/resources/default/configuration/items/flame_elytra.yml +++ b/common-files/src/main/resources/resources/default/configuration/items/flame_elytra.yml @@ -9,8 +9,6 @@ items: wings: flame_elytra data: item-name: <#FF8C00> - model: - template: default:model/simplified_elytra - arguments: - path: minecraft:item/custom/flame_elytra - broken_path: minecraft:item/custom/broken_flame_elytra \ No newline at end of file + textures: + - minecraft:item/custom/flame_elytra + - minecraft:item/custom/flame_elytra_broken \ No newline at end of file diff --git a/common-files/src/main/resources/resources/default/configuration/items/topaz_armor.yml b/common-files/src/main/resources/resources/default/configuration/items/topaz_armor.yml index 8d624a490..ba9876611 100644 --- a/common-files/src/main/resources/resources/default/configuration/items/topaz_armor.yml +++ b/common-files/src/main/resources/resources/default/configuration/items/topaz_armor.yml @@ -14,6 +14,8 @@ templates: slot: ${slot} model: template: default:model/armor_trim + arguments: + texture: minecraft:item/custom/topaz_${part} items: default:topaz_helmet: template: diff --git a/common-files/src/main/resources/resources/default/configuration/items/topaz_tool_weapon.yml b/common-files/src/main/resources/resources/default/configuration/items/topaz_tool_weapon.yml index 04a893078..108d67358 100644 --- a/common-files/src/main/resources/resources/default/configuration/items/topaz_tool_weapon.yml +++ b/common-files/src/main/resources/resources/default/configuration/items/topaz_tool_weapon.yml @@ -7,11 +7,9 @@ items: data: item-name: <#FF8C00> tooltip-style: minecraft:topaz - model: - template: default:model/simplified_fishing_rod_2d - arguments: - path: minecraft:item/custom/topaz_rod - cast_path: minecraft:item/custom/topaz_rod_cast + textures: + - minecraft:item/custom/topaz_rod + - minecraft:item/custom/topaz_rod_cast default:topaz_bow: material: bow settings: @@ -20,13 +18,11 @@ items: data: item-name: <#FF8C00> tooltip-style: minecraft:topaz - model: - template: default:model/simplified_bow_2d - arguments: - path: minecraft:item/custom/topaz_bow - pulling_0_path: minecraft:item/custom/topaz_bow_pulling_0 - pulling_1_path: minecraft:item/custom/topaz_bow_pulling_1 - pulling_2_path: minecraft:item/custom/topaz_bow_pulling_2 + textures: + - minecraft:item/custom/topaz_bow + - minecraft:item/custom/topaz_bow_pulling_0 + - minecraft:item/custom/topaz_bow_pulling_1 + - minecraft:item/custom/topaz_bow_pulling_2 default:topaz_crossbow: material: crossbow settings: @@ -35,15 +31,13 @@ items: data: item-name: <#FF8C00> tooltip-style: minecraft:topaz - model: - template: default:model/simplified_crossbow_2d - arguments: - path: minecraft:item/custom/topaz_crossbow - pulling_0_path: minecraft:item/custom/topaz_crossbow_pulling_0 - pulling_1_path: minecraft:item/custom/topaz_crossbow_pulling_1 - pulling_2_path: minecraft:item/custom/topaz_crossbow_pulling_2 - arrow_path: minecraft:item/custom/topaz_crossbow_arrow - firework_path: minecraft:item/custom/topaz_crossbow_firework + textures: + - minecraft:item/custom/topaz_crossbow + - minecraft:item/custom/topaz_crossbow_pulling_0 + - minecraft:item/custom/topaz_crossbow_pulling_1 + - minecraft:item/custom/topaz_crossbow_pulling_2 + - minecraft:item/custom/topaz_crossbow_arrow + - minecraft:item/custom/topaz_crossbow_firework default:topaz_pickaxe: material: golden_pickaxe settings: @@ -53,10 +47,7 @@ items: item-name: <#FF8C00> tooltip-style: minecraft:topaz max-damage: 64 - model: - template: default:model/simplified_handheld - arguments: - path: minecraft:item/custom/topaz_pickaxe + texture: minecraft:item/custom/topaz_pickaxe default:topaz_axe: material: golden_axe settings: @@ -66,10 +57,7 @@ items: item-name: <#FF8C00> tooltip-style: minecraft:topaz max-damage: 64 - model: - template: default:model/simplified_handheld - arguments: - path: minecraft:item/custom/topaz_axe + texture: minecraft:item/custom/topaz_axe default:topaz_hoe: material: golden_hoe settings: @@ -79,36 +67,25 @@ items: item-name: <#FF8C00> tooltip-style: minecraft:topaz max-damage: 64 - model: - template: default:model/simplified_handheld - arguments: - path: minecraft:item/custom/topaz_hoe + texture: minecraft:item/custom/topaz_hoe default:topaz_shovel: material: golden_shovel settings: - tags: - - default:topaz_tools + tags: ["default:topaz_tools"] data: item-name: <#FF8C00> tooltip-style: minecraft:topaz max-damage: 64 - model: - template: default:model/simplified_handheld - arguments: - path: minecraft:item/custom/topaz_shovel + texture: minecraft:item/custom/topaz_shovel default:topaz_sword: material: golden_sword settings: - tags: - - default:topaz_tools + tags: ["default:topaz_tools"] data: item-name: <#FF8C00> tooltip-style: minecraft:topaz max-damage: 64 - model: - template: default:model/simplified_handheld - arguments: - path: minecraft:item/custom/topaz_sword + texture: minecraft:item/custom/topaz_sword $$>=1.21.4#topaz_trident: default:topaz_trident: material: trident diff --git a/common-files/src/main/resources/resources/default/configuration/templates/block_settings.yml b/common-files/src/main/resources/resources/default/configuration/templates/block_settings.yml new file mode 100644 index 000000000..18e232369 --- /dev/null +++ b/common-files/src/main/resources/resources/default/configuration/templates/block_settings.yml @@ -0,0 +1,216 @@ +templates#settings: + default:settings/solid_1x1x1: + is-suffocating: true + replaceable: false + is-view-blocking: true + is-redstone-conductor: true + can-occlude: true + default:settings/transparent_1x1x1: + is-suffocating: false + replaceable: false + is-view-blocking: false + is-redstone-conductor: false + can-occlude: false + default:settings/sapling: + burnable: false + template: + - default:hardness/none + - default:sound/grass + overrides: + push-reaction: destroy + is-randomly-ticking: true + tags: + - minecraft:mineable/axe + - minecraft:saplings + - minecraft:sword_efficient + default:settings/leaves: + template: + - default:sound/grass + - default:burn_data/leaves + - default:hardness/leaves + - default:settings/transparent_1x1x1 + overrides: + hardness: 0.2 + resistance: 0.2 + push-reaction: destroy + instrument: harp + tags: + - minecraft:mineable/hoe + - minecraft:sword_efficient + - minecraft:leaves + - minecraft:replaceable_by_trees + default:settings/wood: + template: + - default:sound/wood + - default:burn_data/wood + - default:hardness/wood + overrides: + instrument: bass + tags: + - minecraft:mineable/axe + - minecraft:logs_that_burn + - minecraft:logs + - minecraft:completes_find_tree_tutorial + default:settings/planks: + template: + - default:sound/wood + - default:burn_data/planks + - default:hardness/planks + - default:settings/solid_1x1x1 + overrides: + instrument: bass + tags: ["minecraft:mineable/axe"] + default:settings/ore: + template: + - default:sound/stone + - default:settings/solid_1x1x1 + overrides: + hardness: 3.0 + resistance: 3.0 + instrument: basedrum + map-color: 11 + tags: ["minecraft:mineable/pickaxe"] + correct-tools::template: default:pickaxe_power/level_${break_power} + default:settings/deepslate_ore: + template: + - default:sound/deepslate + - default:settings/solid_1x1x1 + - default:hardness/deepslate + overrides: + hardness: 4.5 + resistance: 3.0 + instrument: basedrum + map-color: 59 + tags: ["minecraft:mineable/pickaxe"] + correct-tools::template: default:pickaxe_power/level_${break_power} + +templates#hardness: + default:hardness/none: + hardness: 0 + resistance: 0 + default:hardness/leaves: + hardness: 0.2 + resistance: 0.2 + default:hardness/glass: + hardness: 0.3 + resistance: 0.3 + default:hardness/stone: + hardness: 1.5 + resistance: 6.0 + default:hardness/deepslate: + hardness: 3.0 + resistance: 6.0 + default:hardness/obsidian: + hardness: 50.0 + resistance: 1200.0 + default:hardness/wool: + hardness: 0.8 + resistance: 0.8 + default:hardness/wood: + hardness: 2.0 + resistance: 2.0 + default:hardness/planks: + hardness: 2.0 + resistance: 3.0 + default:hardness/button: + hardness: 0.5 + resistance: 0.5 + default:hardness/melon: + hardness: 1.0 + resistance: 1.0 + +templates#burn_data: + default:burn_data/leaves: + burnable: true + burn-chance: 30 + fire-spread-chance: 60 + default:burn_data/wood: + burnable: true + burn-chance: 5 + fire-spread-chance: 5 + default:burn_data/planks: + burnable: true + burn-chance: 5 + fire-spread-chance: 20 + default:burn_data/wool: + burnable: true + burn-chance: 30 + fire-spread-chance: 60 + default:burn_data/vine: + burnable: true + burn-chance: 15 + fire-spread-chance: 100 + default:burn_data/carpet: + burnable: true + burn-chance: 60 + fire-spread-chance: 20 + default:burn_data/coal: + burnable: true + burn-chance: 5 + fire-spread-chance: 5 + default:burn_data/grass: + burnable: true + burn-chance: 60 + fire-spread-chance: 100 + +templates#sounds: + default:sound/block_template: + sounds: + break: minecraft:block.${block_type}.break + step: minecraft:block.${block_type}.step + place: minecraft:block.${block_type}.place + hit: minecraft:block.${block_type}.hit + fall: minecraft:block.${block_type}.fall + default:sound/crop: + sounds: + break: minecraft:block.crop.break + step: minecraft:block.grass.step + place: minecraft:item.crop.plant + hit: minecraft:block.grass.hit + fall: minecraft:block.grass.fall + default:sound/stem_crop: + sounds: + break: minecraft:block.crop.break + step: minecraft:block.wood.step + place: minecraft:item.crop.plant + hit: minecraft:block.wood.hit + fall: minecraft:block.wood.fall + default:sound/grass: + template: default:sound/block_template + arguments::block_type: grass + default:sound/wood: + template: default:sound/block_template + arguments::block_type: wood + default:sound/stone: + template: default:sound/block_template + arguments::block_type: stone + default:sound/deepslate: + template: default:sound/block_template + arguments::block_type: deepslate + default:sound/glass: + template: default:sound/block_template + arguments::block_type: glass + default:sound/sand: + template: default:sound/block_template + arguments::block_type: sand + default:sound/gravel: + template: default:sound/block_template + arguments::block_type: gravel + default:sound/metal: + template: default:sound/block_template + arguments::block_type: metal + default:sound/snow: + template: default:sound/block_template + arguments::block_type: snow + default:sound/bamboo: + template: default:sound/block_template + arguments::block_type: bamboo + default:sound/vine: + template: default:sound/block_template + arguments::block_type: vine + default:sound/lantern: + template: default:sound/block_template + arguments::block_type: lantern + default:sound/amethyst_block: + template: default:sound/block_template + arguments::block_type: amethyst_block \ No newline at end of file diff --git a/common-files/src/main/resources/resources/default/configuration/templates.yml b/common-files/src/main/resources/resources/default/configuration/templates/block_states.yml similarity index 73% rename from common-files/src/main/resources/resources/default/configuration/templates.yml rename to common-files/src/main/resources/resources/default/configuration/templates/block_states.yml index d22288ef0..df459b4d2 100644 --- a/common-files/src/main/resources/resources/default/configuration/templates.yml +++ b/common-files/src/main/resources/resources/default/configuration/templates/block_states.yml @@ -1,859 +1,4 @@ -# This file contains some useful template data. If you have good ideas, you are welcome to contribute your template! - -# blocks -templates#models#block: - # template: default:model/cube_all - # arguments: - # model: model_path - # texture: texture_path - default:model/cube_all: - path: ${model} - generation: - parent: minecraft:block/cube_all - textures: - all: ${texture} - # template: default:model/simplified_cube_all - # arguments: - # path: [model/texture]_path - default:model/simplified_cube_all: - path: ${path} - generation: - parent: minecraft:block/cube_all - textures: - all: ${path} - # template: default:model/cube_column - # arguments: - # model: model_path - # end_texture: end_texture_path - # side_texture: side_texture_path - default:model/cube_column: - path: ${model} - generation: - parent: minecraft:block/cube_column - textures: - end: ${end_texture} - side: ${side_texture} - # template: default:model/cube - # arguments: - # model: model_path - # particle_texture: particle_texture_path - # down_texture: down_texture_path - # up_texture: up_texture_path - # north_texture: north_texture_path - # east_texture: east_texture_path - # south_texture: south_texture_path - # west_texture: west_texture_path - default:model/cube: - path: ${model} - generation: - parent: minecraft:block/cube_column - textures: - particle: ${particle_texture} - down: ${down_texture} - up: ${up_texture} - north: ${north_texture} - east: ${east_texture} - south: ${south_texture} - west: ${west_texture} - -# 2D items -templates#models#2d: - # template: default:model/generated - # arguments: - # model: model_path - # texture: texture_path - default:model/generated: - type: minecraft:model - path: ${model} - generation: - parent: minecraft:item/generated - textures: - layer0: ${texture} - # template: default:model/simplified_generated - # arguments: - # path: [model/texture]_path - default:model/simplified_generated: - type: minecraft:model - path: ${path} - generation: - parent: minecraft:item/generated - textures: - layer0: ${path} - # template: default:model/2_layer_generated - # arguments: - # model: model_path - # layer0: texture_path - # layer1: texture_path - default:model/2_layer_generated: - type: minecraft:model - path: ${model} - generation: - parent: minecraft:item/generated - textures: - layer0: ${layer0} - layer1: ${layer1} - # template: default:model/handheld - # arguments: - # model: model_path - # texture: texture_path - default:model/handheld: - type: minecraft:model - path: ${model} - generation: - parent: minecraft:item/handheld - textures: - layer0: ${texture} - # template: default:model/simplified_handheld - # arguments: - # path: [model/texture]_path - default:model/simplified_handheld: - type: minecraft:model - path: ${path} - generation: - parent: minecraft:item/handheld - textures: - layer0: ${path} - # template: default:model/elytra - # arguments: - # model: model_path - # broken_model: broken_model_path - # texture: texture_path - # broken_texture: broken_texture_path - default:model/elytra: - type: minecraft:condition - property: minecraft:broken - on-false: - path: ${model} - generation: - parent: minecraft:item/generated - textures: - layer0: ${texture} - on-true: - path: ${broken_model} - generation: - parent: minecraft:item/generated - textures: - layer0: ${broken_texture} - # template: default:model/simplified_elytra - # arguments: - # path: [model/texture]_path - # broken_path: broken_[model/texture]_path - default:model/simplified_elytra: - template: default:model/elytra - arguments: - model: ${path} - texture: ${path} - broken_model: ${broken_path} - broken_texture: ${broken_path} - # template: default:model/armor_trim - # arguments: - # material: armor material type - # part: slot type - default:model/armor_trim: - type: minecraft:select - property: minecraft:trim_material - fallback: - type: minecraft:model - path: minecraft:item/custom/${material}_${part} - generation: - parent: minecraft:item/generated - textures: - layer0: minecraft:item/custom/${material}_${part} - cases: - - when: minecraft:quartz - model: - type: minecraft:model - path: minecraft:item/custom/${material}_${part}_quartz_trim - generation: - parent: minecraft:item/generated - textures: - layer0: minecraft:item/custom/${material}_${part} - layer1: minecraft:trims/items/${part}_trim_quartz - - when: minecraft:iron - model: - type: minecraft:model - path: minecraft:item/custom/${material}_${part}_iron_trim - generation: - parent: minecraft:item/generated - textures: - layer0: minecraft:item/custom/${material}_${part} - layer1: minecraft:trims/items/${part}_trim_iron - - when: minecraft:netherite - model: - type: minecraft:model - path: minecraft:item/custom/${material}_${part}_netherite_trim - generation: - parent: minecraft:item/generated - textures: - layer0: minecraft:item/custom/${material}_${part} - layer1: minecraft:trims/items/${part}_trim_netherite - - when: minecraft:redstone - model: - type: minecraft:model - path: minecraft:item/custom/${material}_${part}_redstone_trim - generation: - parent: minecraft:item/generated - textures: - layer0: minecraft:item/custom/${material}_${part} - layer1: minecraft:trims/items/${part}_trim_redstone - - when: minecraft:copper - model: - type: minecraft:model - path: minecraft:item/custom/${material}_${part}_copper_trim - generation: - parent: minecraft:item/generated - textures: - layer0: minecraft:item/custom/${material}_${part} - layer1: minecraft:trims/items/${part}_trim_copper - - when: minecraft:gold - model: - type: minecraft:model - path: minecraft:item/custom/${material}_${part}_gold_trim - generation: - parent: minecraft:item/generated - textures: - layer0: minecraft:item/custom/${material}_${part} - layer1: minecraft:trims/items/${part}_trim_gold - - when: minecraft:emerald - model: - type: minecraft:model - path: minecraft:item/custom/${material}_${part}_emerald_trim - generation: - parent: minecraft:item/generated - textures: - layer0: minecraft:item/custom/${material}_${part} - layer1: minecraft:trims/items/${part}_trim_emerald - - when: minecraft:diamond - model: - type: minecraft:model - path: minecraft:item/custom/${material}_${part}_diamond_trim - generation: - parent: minecraft:item/generated - textures: - layer0: minecraft:item/custom/${material}_${part} - layer1: minecraft:trims/items/${part}_trim_diamond - - when: minecraft:lapis - model: - type: minecraft:model - path: minecraft:item/custom/${material}_${part}_lapis_trim - generation: - parent: minecraft:item/generated - textures: - layer0: minecraft:item/custom/${material}_${part} - layer1: minecraft:trims/items/${part}_trim_lapis - - when: minecraft:amethyst - model: - type: minecraft:model - path: minecraft:item/custom/${material}_${part}_amethyst_trim - generation: - parent: minecraft:item/generated - textures: - layer0: minecraft:item/custom/${material}_${part} - layer1: minecraft:trims/items/${part}_trim_amethyst - - when: minecraft:resin - model: - type: minecraft:model - path: minecraft:item/custom/${material}_${part}_resin_trim - generation: - parent: minecraft:item/generated - textures: - layer0: minecraft:item/custom/${material}_${part} - layer1: minecraft:trims/items/${part}_trim_resin - -# shield -templates#models#shield: - # template: default:model/shield_3d - # arguments: - # model: shield_model_path - # block_model: shield_block_model_path - default:model/shield_3d: - type: minecraft:condition - property: minecraft:using_item - on-false: - type: minecraft:model - path: ${model} - on-true: - type: minecraft:model - path: ${block_model} - -# fishing rods -templates#models#fishing_rod: - # template: default:model/fishing_rod_3d - # arguments: - # model: rod_model_path - # cast_model: rod_cast_model_path - default:model/fishing_rod_3d: - type: minecraft:condition - property: minecraft:fishing_rod/cast - on-false: - type: minecraft:model - path: ${model} - on-true: - type: minecraft:model - path: ${cast_model} - # template: default:model/fishing_rod_2d - # arguments: - # model: rod_model_path - # cast_model: rod_cast_model_path - # texture: rod_texture_path - # cast_texture: rod_cast_texture_path - default:model/fishing_rod_2d: - type: minecraft:condition - property: minecraft:fishing_rod/cast - on-false: - type: minecraft:model - path: ${model} - generation: - parent: minecraft:item/fishing_rod - textures: - layer0: ${texture} - on-true: - type: minecraft:model - path: ${cast_model} - generation: - parent: minecraft:item/fishing_rod - textures: - layer0: ${cast_texture} - # template: default:model/simplified_fishing_rod_2d - # arguments: - # path: rod_[model/texture]_path - # cast_path: rod_cast_[model/texture]_path - default:model/simplified_fishing_rod_2d: - template: default:model/fishing_rod_2d - arguments: - texture: ${path} - model: ${path} - cast_texture: ${cast_path} - cast_model: ${cast_path} - -# bows -templates#models#bow: - # template: default:model/bow_3d - # arguments: - # model: bow_model_path - # pulling_0_model: bow_pulling_0_model_path - # pulling_1_model: bow_pulling_1_model_path - # pulling_2_model: bow_pulling_2_model_path - default:model/bow_3d: - type: minecraft:condition - property: minecraft:using_item - on-false: - type: minecraft:model - path: ${model} - on-true: - type: minecraft:range_dispatch - property: minecraft:use_duration - scale: 0.05 - entries: - - model: - type: minecraft:model - path: ${pulling_1_model} - threshold: 0.65 - - model: - type: minecraft:model - path: ${pulling_2_model} - threshold: 0.9 - fallback: - type: minecraft:model - path: ${pulling_0_model} - # template: default:model/bow_2d - # arguments: - # model: bow_model_path - # pulling_0_model: bow_pulling_0_model_path - # pulling_1_model: bow_pulling_1_model_path - # pulling_2_model: bow_pulling_2_model_path - # texture: bow_texture_path - # pulling_0_texture: bow_pulling_0_texture_path - # pulling_1_texture: bow_pulling_1_texture_path - # pulling_2_texture: bow_pulling_2_texture_path - default:model/bow_2d: - type: minecraft:condition - property: minecraft:using_item - on-false: - type: minecraft:model - path: ${model} - generation: - parent: minecraft:item/bow - textures: - layer0: ${texture} - on-true: - type: minecraft:range_dispatch - property: minecraft:use_duration - scale: 0.05 - entries: - - model: - type: minecraft:model - path: ${pulling_1_model} - generation: - parent: minecraft:item/bow_pulling_1 - textures: - layer0: ${pulling_1_texture} - threshold: 0.65 - - model: - type: minecraft:model - path: ${pulling_2_model} - generation: - parent: minecraft:item/bow_pulling_2 - textures: - layer0: ${pulling_2_texture} - threshold: 0.9 - fallback: - type: minecraft:model - path: ${pulling_0_model} - generation: - parent: minecraft:item/bow_pulling_0 - textures: - layer0: ${pulling_0_texture} - # template: default:model/simplified_bow_2d - # arguments: - # path: bow_[model/texture]_path - # pulling_0_path: bow_pulling_0_[model/texture]_path - # pulling_1_path: bow_pulling_1_[model/texture]_path - # pulling_2_path: bow_pulling_2_[model/texture]_path - default:model/simplified_bow_2d: - template: default:model/bow_2d - arguments: - model: ${path} - pulling_0_model: ${pulling_0_path} - pulling_1_model: ${pulling_1_path} - pulling_2_model: ${pulling_2_path} - texture: ${path} - pulling_0_texture: ${pulling_0_path} - pulling_1_texture: ${pulling_1_path} - pulling_2_texture: ${pulling_2_path} - -# crossbows -templates#models#crossbow: - # template: default:model/crossbow_3d - # arguments: - # model: crossbow_model_path - # arrow_model: crossbow_arrow_model_path - # firework_model: crossbow_firework_model_path - # pulling_0_model: crossbow_pulling_0_model_path - # pulling_1_model: crossbow_pulling_1_model_path - # pulling_2_model: crossbow_pulling_2_model_path - default:model/crossbow_3d: - type: minecraft:condition - property: minecraft:using_item - on-false: - type: minecraft:select - property: minecraft:charge_type - cases: - - when: arrow - model: - type: minecraft:model - path: ${arrow_model} - - when: rocket - model: - type: minecraft:model - path: ${firework_model} - fallback: - type: minecraft:model - path: ${model} - on-true: - type: minecraft:range_dispatch - property: minecraft:crossbow/pull - entries: - - model: - type: minecraft:model - path: ${pulling_1_model} - threshold: 0.58 - - model: - type: minecraft:model - path: ${pulling_2_model} - threshold: 1.0 - fallback: - type: minecraft:model - path: ${pulling_0_model} - # template: default:model/crossbow_2d - # arguments: - # model: crossbow_model_path - # texture: crossbow_texture_path - # arrow_model: crossbow_arrow_model_path - # arrow_texture: crossbow_arrow_texture_path - # firework_model: crossbow_firework_model_path - # firework_texture: crossbow_firework_texture_path - # pulling_0_model: crossbow_pulling_0_model_path - # pulling_0_texture: crossbow_pulling_0_texture_path - # pulling_1_model: crossbow_pulling_1_model_path - # pulling_1_texture: crossbow_pulling_1_texture_path - # pulling_2_model: crossbow_pulling_2_model_path - # pulling_2_texture: crossbow_pulling_2_texture_path - default:model/crossbow_2d: - type: minecraft:condition - property: minecraft:using_item - on-false: - type: minecraft:select - property: minecraft:charge_type - cases: - - when: arrow - model: - type: minecraft:model - path: ${arrow_model} - generation: - parent: minecraft:item/crossbow_arrow - textures: - layer0: ${arrow_texture} - - when: rocket - model: - type: minecraft:model - path: ${firework_model} - generation: - parent: minecraft:item/crossbow_firework - textures: - layer0: ${firework_texture} - fallback: - type: minecraft:model - path: ${model} - generation: - parent: minecraft:item/crossbow - textures: - layer0: ${texture} - on-true: - type: minecraft:range_dispatch - property: minecraft:crossbow/pull - entries: - - model: - type: minecraft:model - path: ${pulling_1_model} - generation: - parent: minecraft:item/crossbow_pulling_1 - textures: - layer0: ${pulling_1_texture} - threshold: 0.58 - - model: - type: minecraft:model - path: ${pulling_2_model} - generation: - parent: minecraft:item/crossbow_pulling_2 - textures: - layer0: ${pulling_2_texture} - threshold: 1.0 - fallback: - type: minecraft:model - path: ${pulling_0_model} - generation: - parent: minecraft:item/crossbow_pulling_0 - textures: - layer0: ${pulling_0_texture} - # template: default:model/simplified_crossbow_2d - # arguments: - # path: crossbow_[model/texture]_path - # arrow_path: crossbow_arrow_[model/texture]_path - # firework_path: crossbow_firework_[model/texture]_path - # pulling_0_path: crossbow_pulling_0_[model/texture]_path - # pulling_1_path: crossbow_pulling_1_[model/texture]_path - # pulling_2_path: crossbow_pulling_2_[model/texture]_path - default:model/simplified_crossbow_2d: - template: default:model/crossbow_2d - arguments: - model: ${path} - texture: ${path} - arrow_model: ${arrow_path} - arrow_texture: ${arrow_path} - firework_model: ${firework_path} - firework_texture: ${firework_path} - pulling_0_model: ${pulling_0_path} - pulling_0_texture: ${pulling_0_path} - pulling_1_model: ${pulling_1_path} - pulling_1_texture: ${pulling_1_path} - pulling_2_model: ${pulling_2_path} - pulling_2_texture: ${pulling_2_path} - -# sounds -templates#settings#sounds: - default:sound/block_template: - sounds: - break: minecraft:block.${block_type}.break - step: minecraft:block.${block_type}.step - place: minecraft:block.${block_type}.place - hit: minecraft:block.${block_type}.hit - fall: minecraft:block.${block_type}.fall - default:sound/crop: - sounds: - break: minecraft:block.crop.break - step: minecraft:block.grass.step - place: minecraft:item.crop.plant - hit: minecraft:block.grass.hit - fall: minecraft:block.grass.fall - default:sound/stem_crop: - sounds: - break: minecraft:block.crop.break - step: minecraft:block.wood.step - place: minecraft:item.crop.plant - hit: minecraft:block.wood.hit - fall: minecraft:block.wood.fall - default:sound/grass: - template: default:sound/block_template - arguments: - block_type: grass - default:sound/wood: - template: default:sound/block_template - arguments: - block_type: wood - default:sound/stone: - template: default:sound/block_template - arguments: - block_type: stone - default:sound/deepslate: - template: default:sound/block_template - arguments: - block_type: deepslate - default:sound/glass: - template: default:sound/block_template - arguments: - block_type: glass - default:sound/sand: - template: default:sound/block_template - arguments: - block_type: sand - default:sound/gravel: - template: default:sound/block_template - arguments: - block_type: gravel - default:sound/metal: - template: default:sound/block_template - arguments: - block_type: metal - default:sound/snow: - template: default:sound/block_template - arguments: - block_type: snow - default:sound/bamboo: - template: default:sound/block_template - arguments: - block_type: bamboo - default:sound/vine: - template: default:sound/block_template - arguments: - block_type: vine - default:sound/lantern: - template: default:sound/block_template - arguments: - block_type: lantern - default:sound/amethyst_block: - template: default:sound/block_template - arguments: - block_type: amethyst_block - -# burn data -templates#settings#burn: - default:burn_data/leaves: - burnable: true - burn-chance: 30 - fire-spread-chance: 60 - default:burn_data/wood: - burnable: true - burn-chance: 5 - fire-spread-chance: 5 - default:burn_data/planks: - burnable: true - burn-chance: 5 - fire-spread-chance: 20 - default:burn_data/wool: - burnable: true - burn-chance: 30 - fire-spread-chance: 60 - default:burn_data/vine: - burnable: true - burn-chance: 15 - fire-spread-chance: 100 - default:burn_data/carpet: - burnable: true - burn-chance: 60 - fire-spread-chance: 20 - default:burn_data/coal: - burnable: true - burn-chance: 5 - fire-spread-chance: 5 - default:burn_data/grass: - burnable: true - burn-chance: 60 - fire-spread-chance: 100 - -# hardness & resistance -templates#settings#hardness: - default:hardness/none: - hardness: 0 - resistance: 0 - default:hardness/leaves: - hardness: 0.2 - resistance: 0.2 - default:hardness/glass: - hardness: 0.3 - resistance: 0.3 - default:hardness/stone: - hardness: 1.5 - resistance: 6.0 - default:hardness/deepslate: - hardness: 3.0 - resistance: 6.0 - default:hardness/obsidian: - hardness: 50.0 - resistance: 1200.0 - default:hardness/wool: - hardness: 0.8 - resistance: 0.8 - default:hardness/wood: - hardness: 2.0 - resistance: 2.0 - default:hardness/planks: - hardness: 2.0 - resistance: 3.0 - default:hardness/button: - hardness: 0.5 - resistance: 0.5 - default:hardness/melon: - hardness: 1.0 - resistance: 1.0 - -# break level -templates#settings#break_level: - default:pickaxe_power/level_1: - correct-tools: - - minecraft:wooden_pickaxe - - minecraft:stone_pickaxe - - minecraft:iron_pickaxe - - minecraft:golden_pickaxe - - minecraft:diamond_pickaxe - - minecraft:netherite_pickaxe - - default:topaz_pickaxe - default:pickaxe_power/level_2: - correct-tools: - - minecraft:stone_pickaxe - - minecraft:iron_pickaxe - - minecraft:golden_pickaxe - - minecraft:diamond_pickaxe - - minecraft:netherite_pickaxe - - default:topaz_pickaxe - default:pickaxe_power/level_3: - correct-tools: - - minecraft:iron_pickaxe - - minecraft:golden_pickaxe - - minecraft:diamond_pickaxe - - minecraft:netherite_pickaxe - - default:topaz_pickaxe - default:pickaxe_power/level_4: - correct-tools: - - minecraft:diamond_pickaxe - - minecraft:netherite_pickaxe - -# block settings -templates#settings#blocks: - default:settings/middle_click_pick_itself: - item: ${__NAMESPACE__}:${__ID__} - default:settings/solid_1x1x1: - is-suffocating: true - replaceable: false - is-view-blocking: true - is-redstone-conductor: true - can-occlude: true - default:settings/transparent_1x1x1: - is-suffocating: false - replaceable: false - is-view-blocking: false - can-occlude: false - # sapling - default:settings/sapling: - burnable: false - template: - - default:hardness/none - - default:sound/grass - overrides: - push-reaction: destroy - is-randomly-ticking: true - map-color: 7 - tags: - - minecraft:mineable/axe - - minecraft:saplings - - minecraft:sword_efficient - # leaves - default:settings/leaves: - template: - - default:sound/grass - - default:burn_data/leaves - - default:hardness/leaves - overrides: - hardness: 0.2 - resistance: 0.2 - push-reaction: destroy - replaceable: false - is-redstone-conductor: false - is-suffocating: false - instrument: harp - tags: - - minecraft:mineable/hoe - - minecraft:sword_efficient - - minecraft:leaves - - minecraft:replaceable_by_trees - # wood - default:settings/wood: - template: - - default:sound/wood - - default:burn_data/wood - - default:hardness/wood - overrides: - push-reaction: normal - replaceable: false - is-redstone-conductor: true - is-suffocating: true - instrument: bass - can-occlude: true - tags: - - minecraft:mineable/axe - - minecraft:logs_that_burn - - minecraft:logs - - minecraft:completes_find_tree_tutorial - # plank - default:settings/planks: - template: - - default:sound/wood - - default:burn_data/planks - - default:hardness/planks - overrides: - push-reaction: normal - replaceable: false - is-redstone-conductor: true - is-suffocating: true - instrument: bass - can-occlude: true - tags: - - minecraft:mineable/axe - # ore - default:settings/ore: - template: - - default:sound/stone - - default:pickaxe_power/level_${break_power} - overrides: - hardness: 3.0 - resistance: 3.0 - push-reaction: normal - is-redstone-conductor: true - is-suffocating: true - instrument: basedrum - can-occlude: true - map-color: 11 - tags: - - minecraft:mineable/pickaxe - # deepslate ore - default:settings/deepslate_ore: - template: - - default:sound/deepslate - - default:pickaxe_power/level_${break_power} - overrides: - hardness: 4.5 - resistance: 3.0 - push-reaction: normal - is-redstone-conductor: true - is-suffocating: true - instrument: basedrum - can-occlude: true - map-color: 59 - tags: - - minecraft:mineable/pickaxe - -# block states -templates#block_states: +templates: # pillar/log blocks default:block_state/pillar: properties: @@ -938,18 +83,15 @@ templates#block_states: # any leaves block default:block_state/leaves: template: default:block_state/__leaves__ - arguments: - auto_state: leaves + arguments::auto_state: leaves # tintable leaves block default:block_state/tintable_leaves: template: default:block_state/__leaves__ - arguments: - auto_state: tintable_leaves + arguments::auto_state: tintable_leaves # non-tintable leaves block default:block_state/non_tintable_leaves: template: default:block_state/__leaves__ - arguments: - auto_state: non_tintable_leaves + arguments::auto_state: non_tintable_leaves # trapdoor block default:block_state/trapdoor: properties: @@ -3099,331 +2241,4 @@ templates#block_states: east=false,north=true,south=true,waterlogged=true,west=true: appearance: east=false,north=true,south=true,waterlogged=true,west=true east=true,north=true,south=true,waterlogged=true,west=true: - appearance: east=true,north=true,south=true,waterlogged=true,west=true - -# recipes -templates#recipes: - default:recipe/planks: - type: shapeless - category: building - group: planks - ingredients: - - '#default:${wood_type}_logs' - result: - id: default:${wood_type}_planks - count: 4 - default:recipe/log_2_wood: - type: shaped - category: building - group: bark - pattern: - - AA - - AA - ingredients: - A: default:${wood_type}_log - result: - id: default:${wood_type}_wood - count: 3 - default:recipe/smelting_ore: - type: smelting - experience: ${exp} - category: misc - group: topaz - time: 200 - ingredient: ${ingredient} - result: - id: ${result} - count: 1 - default:recipe/blasting_ore: - type: blasting - experience: ${exp} - category: misc - group: topaz - time: 100 - ingredient: ${ingredient} - result: - id: ${result} - count: 1 - -# loot tables -templates#loot_tables: - - # drop itself - - # template: default:loot_table/self - default:loot_table/self: - pools: - - rolls: 1 - conditions: - - type: survives_explosion - entries: - - type: item - item: ${__NAMESPACE__}:${__ID__} - - # drop one item - - # template: default:loot_table/basic - # arguments: - # item: the item - default:loot_table/basic: - pools: - - rolls: 1 - conditions: - - type: survives_explosion - entries: - - type: item - item: ${item} - - # drop the original furniture item or a fallback item - - # template: default:loot_table/furniture - # arguments: - # item: the fallback item - default:loot_table/furniture: - pools: - - rolls: 1 - entries: - - type: furniture_item - item: ${item} - - # drop the door - - # template: default:loot_table/door - default:loot_table/door: - pools: - - rolls: 1 - entries: - - type: item - item: ${__NAMESPACE__}:${__ID__} - conditions: - - type: match_block_property - properties: - half: lower - - # drop with silk touch - - # template: default:loot_table/silk_touch - # arguments: - # item: the item - default:loot_table/silk_touch: - pools: - - rolls: 1 - conditions: - - type: enchantment - predicate: minecraft:silk_touch>=1 - entries: - - type: item - item: ${item} - - # drop 1/2 slabs - - # template: default:loot_table/slab - default:loot_table/slab: - pools: - - rolls: 1 - entries: - - type: item - item: ${__NAMESPACE__}:${__ID__} - functions: - - type: set_count - count: 2 - add: false - conditions: - - type: match_block_property - properties: - type: double - - type: explosion_decay - - # crop drops - - # - # This template is suitable for crops such as wheat and beetroot - # - # template: default:loot_table/seed_crop - # arguments: - # crop_item: the mature crop item - # crop_item_count: quantity of mature crop items - # crop_seed: the seed item of the crop - # extra_seed_count: additional seeds dropped when crop reaches maturity - # ripe_age: the max age - default:loot_table/seed_crop: - pools: - - rolls: 1 - entries: - - type: alternatives - children: - - type: item - item: ${crop_item} - conditions: - - type: match_block_property - properties: - age: ${ripe_age} - functions: - - type: set_count - add: false - count: ${crop_item_count:-1} - - type: item - item: ${crop_seed} - - rolls: 1 - conditions: - - type: match_block_property - properties: - age: ${ripe_age} - entries: - - type: item - item: ${crop_seed} - functions: - - type: apply_bonus - enchantment: minecraft:fortune - formula: - type: binomial_with_bonus_count - extra: ${extra_seed_count:-3} - probability: 0.5714286 - # - # This template is suitable for crops like carrots and potatoes. - # - # template: default:loot_table/crop - # arguments: - # crop_item: the crop item - # extra_crop_count: additional crops dropped when crop reaches maturity - # ripe_age: the max age - default:loot_table/crop: - pools: - - rolls: 1 - entries: - - type: item - item: ${crop_item} - - rolls: 1 - conditions: - - type: match_block_property - properties: - age: ${ripe_age} - entries: - - type: item - item: ${crop_item} - functions: - - type: apply_bonus - enchantment: minecraft:fortune - formula: - type: binomial_with_bonus_count - extra: ${extra_crop_count:-3} - probability: 0.5714286 - - # ore drops - - # template: default:loot_table/ore - # arguments: - # ore_block: the ore block - # ore_drop: the drops of the ore - # min_exp: the min exp to drop - # max_exp: the max exp to drop - default:loot_table/ore: - pools: - - rolls: 1 - entries: - - type: alternatives - children: - - type: item - item: ${ore_block} - conditions: - - type: enchantment - predicate: minecraft:silk_touch>=1 - - type: item - item: ${ore_drop} - functions: - - type: apply_bonus - enchantment: minecraft:fortune - formula: - type: ore_drops - - type: explosion_decay - - type: drop_exp - count: - type: uniform - min: ${min_exp:-2} - max: ${max_exp:-4} - - # template: default:loot_table/ore_no_exp - # arguments: - # ore_block: the ore block - # ore_drop: the drops of the ore - default:loot_table/ore_no_exp: - pools: - - rolls: 1 - entries: - - type: alternatives - children: - - type: item - item: ${ore_block} - conditions: - - type: enchantment - predicate: minecraft:silk_touch>=1 - - type: item - item: ${ore_drop} - functions: - - type: apply_bonus - enchantment: minecraft:fortune - formula: - type: ore_drops - - type: explosion_decay - - # leaves drops - - # template: default:loot_table/leaves - # arguments: - # leaves: the leaves block - # sapling: the sapling item - default:loot_table/leaves: - pools: - - rolls: 1 - entries: - - type: alternatives - children: - - type: item - item: ${leaves} - conditions: - - type: any_of - terms: - - type: match_item - id: minecraft:shears - - type: enchantment - predicate: minecraft:silk_touch>=1 - - type: item - item: ${sapling} - conditions: - - type: survives_explosion - - type: table_bonus - enchantment: minecraft:fortune - chances: - - 0.05 - - 0.0625 - - 0.083333333 - - 0.1 - - rolls: 1 - conditions: - - type: inverted - term: - type: any_of - terms: - - type: match_item - id: minecraft:shears - - type: enchantment - predicate: minecraft:silk_touch>=1 - entries: - - type: item - item: minecraft:stick - conditions: - - type: table_bonus - enchantment: minecraft:fortune - chances: - - 0.02 - - 0.022222222 - - 0.025 - - 0.033333333 - - 0.1 - functions: - - type: set_count - count: - type: uniform - min: 1 - max: 2 - - type: explosion_decay + appearance: east=true,north=true,south=true,waterlogged=true,west=true \ No newline at end of file diff --git a/common-files/src/main/resources/resources/default/configuration/templates/loot_tables.yml b/common-files/src/main/resources/resources/default/configuration/templates/loot_tables.yml new file mode 100644 index 000000000..99a366d26 --- /dev/null +++ b/common-files/src/main/resources/resources/default/configuration/templates/loot_tables.yml @@ -0,0 +1,270 @@ +templates: + + # Drop itself. + # Suitable for the vast majority of loot items. + # Only requires the template ID to be filled in during use, with no parameter requirements. + + # template: default:loot_table/self + default:loot_table/self: + pools: + - rolls: 1 + conditions: + - type: survives_explosion + entries: + - type: item + item: ${__NAMESPACE__}:${__ID__} + + # Drop the original furniture item or a fallback item. + + # template: default:loot_table/furniture + # arguments: + # item: the fallback item + default:loot_table/furniture: + pools: + - rolls: 1 + entries: + - type: furniture_item + item: ${item} + + # Drop one or more items. + + # template: default:loot_table/basic + # arguments: + # item: the item + # count: the amount of the item + default:loot_table/basic: + pools: + - rolls: 1 + conditions: + - type: survives_explosion + entries: + - type: item + item: ${item} + functions: + - type: set_count + add: false + count: ${count:-1} + + # Drop the door. + # Since a door consists of two blocks, if both of them have drop items, it will cause duplication. + + # template: default:loot_table/door + default:loot_table/door: + pools: + - rolls: 1 + entries: + - type: item + item: ${__NAMESPACE__}:${__ID__} + conditions: + - type: match_block_property + properties: + half: lower + + # Drop with silk touch + # This template is used for loot that only drops when harvested with Silk Touch. + + # template: default:loot_table/silk_touch + # arguments: + # item: the item + # count: the amount of the item + default:loot_table/silk_touch: + pools: + - rolls: 1 + conditions: + - type: enchantment + predicate: minecraft:silk_touch>=1 + entries: + - type: item + item: ${item} + functions: + - type: set_count + add: false + count: ${count:-1} + + # Drop slabs + # When two slabs are stacked, the loot table should be set to drop two items. + + # template: default:loot_table/slab + default:loot_table/slab: + pools: + - rolls: 1 + entries: + - type: item + item: ${__NAMESPACE__}:${__ID__} + functions: + - type: set_count + count: 2 + add: false + conditions: + - type: match_block_property + properties: + type: double + - type: explosion_decay + + # This loot table is for crops that are grown from seeds. Example: wheat. + + # template: default:loot_table/seed_crop + # arguments: + # crop_item: the mature crop item + # crop_item_count: quantity of mature crop items + # crop_seed: the seed item of the crop + # extra_seed_count: additional seeds dropped when crop reaches maturity + # ripe_age: the max age + default:loot_table/seed_crop: + pools: + - rolls: 1 + entries: + - type: alternatives + children: + - type: item + item: ${crop_item} + conditions: + - type: match_block_property + properties: + age: ${ripe_age} + functions: + - type: set_count + add: false + count: ${crop_item_count:-1} + - type: item + item: ${crop_seed} + - rolls: 1 + conditions: + - type: match_block_property + properties: + age: ${ripe_age} + entries: + - type: item + item: ${crop_seed} + functions: + - type: apply_bonus + enchantment: minecraft:fortune + formula: + type: binomial_with_bonus_count + extra: ${extra_seed_count:-3} + probability: 0.5714286 + + # This loot table is for crops that are grown from themselves. Example: carrots. + + # template: default:loot_table/crop + # arguments: + # crop_item: the crop item + # extra_crop_count: additional crops dropped when crop reaches maturity + # ripe_age: the max age + default:loot_table/crop: + pools: + - rolls: 1 + entries: + - type: item + item: ${crop_item} + - rolls: 1 + conditions: + - type: match_block_property + properties: + age: ${ripe_age} + entries: + - type: item + item: ${crop_item} + functions: + - type: apply_bonus + enchantment: minecraft:fortune + formula: + type: binomial_with_bonus_count + extra: ${extra_crop_count:-3} + probability: 0.5714286 + + # When Silk Touch is used, it drops the ore block itself. When Fortune is used, it increases the drops of the materials. + + # template: default:loot_table/ore + # arguments: + # ore_block: the ore block + # ore_drop: the drops of the ore + # ore_drop_count: the amount of the ore materials + # exp: the exp to drop + default:loot_table/ore: + pools: + - rolls: 1 + entries: + - type: alternatives + children: + - type: item + item: ${ore_block} + conditions: + - type: enchantment + predicate: minecraft:silk_touch>=1 + - type: item + item: ${ore_drop} + functions: + - type: set_count + count: ${ore_drop_count:-1} + add: false + - type: apply_bonus + enchantment: minecraft:fortune + formula: + type: ore_drops + - type: explosion_decay + - type: drop_exp + count: ${exp:-2~4} + + # Using Silk Touch or shears will cause the leaves block itself to drop. + # Using Fortune, however, increases the drop rates of sticks and saplings. + + # template: default:loot_table/leaves + # arguments: + # leaves: the leaves block + # sapling: the sapling item + default:loot_table/leaves: + pools: + - rolls: 1 + entries: + - type: alternatives + children: + - type: item + item: ${leaves} + conditions: + - type: any_of + terms: + - type: match_item + id: minecraft:shears + - type: enchantment + predicate: minecraft:silk_touch>=1 + - type: item + item: ${sapling} + conditions: + - type: survives_explosion + - type: table_bonus + enchantment: minecraft:fortune + chances: + - 0.05 + - 0.0625 + - 0.083333333 + - 0.1 + - rolls: 1 + conditions: + - type: inverted + term: + type: any_of + terms: + - type: match_item + id: minecraft:shears + - type: enchantment + predicate: minecraft:silk_touch>=1 + entries: + - type: item + item: minecraft:stick + conditions: + - type: table_bonus + enchantment: minecraft:fortune + chances: + - 0.02 + - 0.022222222 + - 0.025 + - 0.033333333 + - 0.1 + functions: + - type: set_count + count: + type: uniform + min: 1 + max: 2 + - type: explosion_decay diff --git a/common-files/src/main/resources/resources/default/configuration/templates/models.yml b/common-files/src/main/resources/resources/default/configuration/templates/models.yml new file mode 100644 index 000000000..8c681c2c0 --- /dev/null +++ b/common-files/src/main/resources/resources/default/configuration/templates/models.yml @@ -0,0 +1,560 @@ +# blocks +templates#models#block: + # template: default:model/cube_all + # arguments: + # model: model_path + # texture: texture_path + default:model/cube_all: + path: ${model} + generation: + parent: minecraft:block/cube_all + textures: + all: ${texture} + # template: default:model/simplified_cube_all + # arguments: + # path: [model/texture]_path + default:model/simplified_cube_all: + path: ${path} + generation: + parent: minecraft:block/cube_all + textures: + all: ${path} + # template: default:model/cube_column + # arguments: + # model: model_path + # end_texture: end_texture_path + # side_texture: side_texture_path + default:model/cube_column: + path: ${model} + generation: + parent: minecraft:block/cube_column + textures: + end: ${end_texture} + side: ${side_texture} + # template: default:model/cube + # arguments: + # model: model_path + # particle_texture: particle_texture_path + # down_texture: down_texture_path + # up_texture: up_texture_path + # north_texture: north_texture_path + # east_texture: east_texture_path + # south_texture: south_texture_path + # west_texture: west_texture_path + default:model/cube: + path: ${model} + generation: + parent: minecraft:block/cube_column + textures: + particle: ${particle_texture} + down: ${down_texture} + up: ${up_texture} + north: ${north_texture} + east: ${east_texture} + south: ${south_texture} + west: ${west_texture} + +# 2D items +templates#models#2d: + # template: default:model/generated + # arguments: + # model: model_path + # texture: texture_path + default:model/generated: + type: minecraft:model + path: ${model} + generation: + parent: minecraft:item/generated + textures: + layer0: ${texture} + # template: default:model/simplified_generated + # arguments: + # path: [model/texture]_path + default:model/simplified_generated: + type: minecraft:model + path: ${path} + generation: + parent: minecraft:item/generated + textures: + layer0: ${path} + # template: default:model/2_layer_generated + # arguments: + # model: model_path + # layer0: texture_path + # layer1: texture_path + default:model/2_layer_generated: + type: minecraft:model + path: ${model} + generation: + parent: minecraft:item/generated + textures: + layer0: ${layer0} + layer1: ${layer1} + # template: default:model/handheld + # arguments: + # model: model_path + # texture: texture_path + default:model/handheld: + type: minecraft:model + path: ${model} + generation: + parent: minecraft:item/handheld + textures: + layer0: ${texture} + # template: default:model/simplified_handheld + # arguments: + # path: [model/texture]_path + default:model/simplified_handheld: + type: minecraft:model + path: ${path} + generation: + parent: minecraft:item/handheld + textures: + layer0: ${path} + # template: default:model/elytra + # arguments: + # model: model_path + # broken_model: broken_model_path + # texture: texture_path + # broken_texture: broken_texture_path + default:model/elytra: + type: minecraft:condition + property: minecraft:broken + on-false: + path: ${model} + generation: + parent: minecraft:item/generated + textures: + layer0: ${texture} + on-true: + path: ${broken_model} + generation: + parent: minecraft:item/generated + textures: + layer0: ${broken_texture} + # template: default:model/simplified_elytra + # arguments: + # path: [model/texture]_path + # broken_path: broken_[model/texture]_path + default:model/simplified_elytra: + template: default:model/elytra + arguments: + model: ${path} + texture: ${path} + broken_model: ${broken_path} + broken_texture: ${broken_path} + # template: default:model/armor_trim + # arguments: + # material: armor material type + # part: slot type + # texture: the texture path of the armor item + default:model/armor_trim: + type: minecraft:select + property: minecraft:trim_material + fallback: + type: minecraft:model + path: ${__NAMESPACE__}:item/${material}_${part} + generation: + parent: minecraft:item/generated + textures: + layer0: ${texture} + cases: + - when: minecraft:quartz + model: + type: minecraft:model + path: ${__NAMESPACE__}:item/${material}_${part}_quartz_trim + generation: + parent: minecraft:item/generated + textures: + layer0: ${texture} + layer1: minecraft:trims/items/${part}_trim_quartz + - when: minecraft:iron + model: + type: minecraft:model + path: ${__NAMESPACE__}:item/${material}_${part}_iron_trim + generation: + parent: minecraft:item/generated + textures: + layer0: ${texture} + layer1: minecraft:trims/items/${part}_trim_iron + - when: minecraft:netherite + model: + type: minecraft:model + path: ${__NAMESPACE__}:item/${material}_${part}_netherite_trim + generation: + parent: minecraft:item/generated + textures: + layer0: ${texture} + layer1: minecraft:trims/items/${part}_trim_netherite + - when: minecraft:redstone + model: + type: minecraft:model + path: ${__NAMESPACE__}:item/${material}_${part}_redstone_trim + generation: + parent: minecraft:item/generated + textures: + layer0: ${texture} + layer1: minecraft:trims/items/${part}_trim_redstone + - when: minecraft:copper + model: + type: minecraft:model + path: ${__NAMESPACE__}:item/${material}_${part}_copper_trim + generation: + parent: minecraft:item/generated + textures: + layer0: ${texture} + layer1: minecraft:trims/items/${part}_trim_copper + - when: minecraft:gold + model: + type: minecraft:model + path: ${__NAMESPACE__}:item/${material}_${part}_gold_trim + generation: + parent: minecraft:item/generated + textures: + layer0: ${texture} + layer1: minecraft:trims/items/${part}_trim_gold + - when: minecraft:emerald + model: + type: minecraft:model + path: ${__NAMESPACE__}:item/${material}_${part}_emerald_trim + generation: + parent: minecraft:item/generated + textures: + layer0: ${texture} + layer1: minecraft:trims/items/${part}_trim_emerald + - when: minecraft:diamond + model: + type: minecraft:model + path: ${__NAMESPACE__}:item/${material}_${part}_diamond_trim + generation: + parent: minecraft:item/generated + textures: + layer0: ${texture} + layer1: minecraft:trims/items/${part}_trim_diamond + - when: minecraft:lapis + model: + type: minecraft:model + path: ${__NAMESPACE__}:item/${material}_${part}_lapis_trim + generation: + parent: minecraft:item/generated + textures: + layer0: ${texture} + layer1: minecraft:trims/items/${part}_trim_lapis + - when: minecraft:amethyst + model: + type: minecraft:model + path: ${__NAMESPACE__}:item/${material}_${part}_amethyst_trim + generation: + parent: minecraft:item/generated + textures: + layer0: ${texture} + layer1: minecraft:trims/items/${part}_trim_amethyst + - when: minecraft:resin + model: + type: minecraft:model + path: ${__NAMESPACE__}:item/${material}_${part}_resin_trim + generation: + parent: minecraft:item/generated + textures: + layer0: ${texture} + layer1: minecraft:trims/items/${part}_trim_resin + +# shield +templates#models#shield: + # template: default:model/shield_3d + # arguments: + # model: shield_model_path + # block_model: shield_block_model_path + default:model/shield_3d: + type: minecraft:condition + property: minecraft:using_item + on-false: + type: minecraft:model + path: ${model} + on-true: + type: minecraft:model + path: ${block_model} + +# fishing rods +templates#models#fishing_rod: + # template: default:model/fishing_rod_3d + # arguments: + # model: rod_model_path + # cast_model: rod_cast_model_path + default:model/fishing_rod_3d: + type: minecraft:condition + property: minecraft:fishing_rod/cast + on-false: + type: minecraft:model + path: ${model} + on-true: + type: minecraft:model + path: ${cast_model} + # template: default:model/fishing_rod_2d + # arguments: + # model: rod_model_path + # cast_model: rod_cast_model_path + # texture: rod_texture_path + # cast_texture: rod_cast_texture_path + default:model/fishing_rod_2d: + type: minecraft:condition + property: minecraft:fishing_rod/cast + on-false: + type: minecraft:model + path: ${model} + generation: + parent: minecraft:item/fishing_rod + textures: + layer0: ${texture} + on-true: + type: minecraft:model + path: ${cast_model} + generation: + parent: minecraft:item/fishing_rod + textures: + layer0: ${cast_texture} + # template: default:model/simplified_fishing_rod_2d + # arguments: + # path: rod_[model/texture]_path + # cast_path: rod_cast_[model/texture]_path + default:model/simplified_fishing_rod_2d: + template: default:model/fishing_rod_2d + arguments: + texture: ${path} + model: ${path} + cast_texture: ${cast_path} + cast_model: ${cast_path} + +# bows +templates#models#bow: + # template: default:model/bow_3d + # arguments: + # model: bow_model_path + # pulling_0_model: bow_pulling_0_model_path + # pulling_1_model: bow_pulling_1_model_path + # pulling_2_model: bow_pulling_2_model_path + default:model/bow_3d: + type: minecraft:condition + property: minecraft:using_item + on-false: + type: minecraft:model + path: ${model} + on-true: + type: minecraft:range_dispatch + property: minecraft:use_duration + scale: 0.05 + entries: + - model: + type: minecraft:model + path: ${pulling_1_model} + threshold: 0.65 + - model: + type: minecraft:model + path: ${pulling_2_model} + threshold: 0.9 + fallback: + type: minecraft:model + path: ${pulling_0_model} + # template: default:model/bow_2d + # arguments: + # model: bow_model_path + # pulling_0_model: bow_pulling_0_model_path + # pulling_1_model: bow_pulling_1_model_path + # pulling_2_model: bow_pulling_2_model_path + # texture: bow_texture_path + # pulling_0_texture: bow_pulling_0_texture_path + # pulling_1_texture: bow_pulling_1_texture_path + # pulling_2_texture: bow_pulling_2_texture_path + default:model/bow_2d: + type: minecraft:condition + property: minecraft:using_item + on-false: + type: minecraft:model + path: ${model} + generation: + parent: minecraft:item/bow + textures: + layer0: ${texture} + on-true: + type: minecraft:range_dispatch + property: minecraft:use_duration + scale: 0.05 + entries: + - model: + type: minecraft:model + path: ${pulling_1_model} + generation: + parent: minecraft:item/bow_pulling_1 + textures: + layer0: ${pulling_1_texture} + threshold: 0.65 + - model: + type: minecraft:model + path: ${pulling_2_model} + generation: + parent: minecraft:item/bow_pulling_2 + textures: + layer0: ${pulling_2_texture} + threshold: 0.9 + fallback: + type: minecraft:model + path: ${pulling_0_model} + generation: + parent: minecraft:item/bow_pulling_0 + textures: + layer0: ${pulling_0_texture} + # template: default:model/simplified_bow_2d + # arguments: + # path: bow_[model/texture]_path + # pulling_0_path: bow_pulling_0_[model/texture]_path + # pulling_1_path: bow_pulling_1_[model/texture]_path + # pulling_2_path: bow_pulling_2_[model/texture]_path + default:model/simplified_bow_2d: + template: default:model/bow_2d + arguments: + model: ${path} + pulling_0_model: ${pulling_0_path} + pulling_1_model: ${pulling_1_path} + pulling_2_model: ${pulling_2_path} + texture: ${path} + pulling_0_texture: ${pulling_0_path} + pulling_1_texture: ${pulling_1_path} + pulling_2_texture: ${pulling_2_path} + +# crossbows +templates#models#crossbow: + # template: default:model/crossbow_3d + # arguments: + # model: crossbow_model_path + # arrow_model: crossbow_arrow_model_path + # firework_model: crossbow_firework_model_path + # pulling_0_model: crossbow_pulling_0_model_path + # pulling_1_model: crossbow_pulling_1_model_path + # pulling_2_model: crossbow_pulling_2_model_path + default:model/crossbow_3d: + type: minecraft:condition + property: minecraft:using_item + on-false: + type: minecraft:select + property: minecraft:charge_type + cases: + - when: arrow + model: + type: minecraft:model + path: ${arrow_model} + - when: rocket + model: + type: minecraft:model + path: ${firework_model} + fallback: + type: minecraft:model + path: ${model} + on-true: + type: minecraft:range_dispatch + property: minecraft:crossbow/pull + entries: + - model: + type: minecraft:model + path: ${pulling_1_model} + threshold: 0.58 + - model: + type: minecraft:model + path: ${pulling_2_model} + threshold: 1.0 + fallback: + type: minecraft:model + path: ${pulling_0_model} + # template: default:model/crossbow_2d + # arguments: + # model: crossbow_model_path + # texture: crossbow_texture_path + # arrow_model: crossbow_arrow_model_path + # arrow_texture: crossbow_arrow_texture_path + # firework_model: crossbow_firework_model_path + # firework_texture: crossbow_firework_texture_path + # pulling_0_model: crossbow_pulling_0_model_path + # pulling_0_texture: crossbow_pulling_0_texture_path + # pulling_1_model: crossbow_pulling_1_model_path + # pulling_1_texture: crossbow_pulling_1_texture_path + # pulling_2_model: crossbow_pulling_2_model_path + # pulling_2_texture: crossbow_pulling_2_texture_path + default:model/crossbow_2d: + type: minecraft:condition + property: minecraft:using_item + on-false: + type: minecraft:select + property: minecraft:charge_type + cases: + - when: arrow + model: + type: minecraft:model + path: ${arrow_model} + generation: + parent: minecraft:item/crossbow_arrow + textures: + layer0: ${arrow_texture} + - when: rocket + model: + type: minecraft:model + path: ${firework_model} + generation: + parent: minecraft:item/crossbow_firework + textures: + layer0: ${firework_texture} + fallback: + type: minecraft:model + path: ${model} + generation: + parent: minecraft:item/crossbow + textures: + layer0: ${texture} + on-true: + type: minecraft:range_dispatch + property: minecraft:crossbow/pull + entries: + - model: + type: minecraft:model + path: ${pulling_1_model} + generation: + parent: minecraft:item/crossbow_pulling_1 + textures: + layer0: ${pulling_1_texture} + threshold: 0.58 + - model: + type: minecraft:model + path: ${pulling_2_model} + generation: + parent: minecraft:item/crossbow_pulling_2 + textures: + layer0: ${pulling_2_texture} + threshold: 1.0 + fallback: + type: minecraft:model + path: ${pulling_0_model} + generation: + parent: minecraft:item/crossbow_pulling_0 + textures: + layer0: ${pulling_0_texture} + # template: default:model/simplified_crossbow_2d + # arguments: + # path: crossbow_[model/texture]_path + # arrow_path: crossbow_arrow_[model/texture]_path + # firework_path: crossbow_firework_[model/texture]_path + # pulling_0_path: crossbow_pulling_0_[model/texture]_path + # pulling_1_path: crossbow_pulling_1_[model/texture]_path + # pulling_2_path: crossbow_pulling_2_[model/texture]_path + default:model/simplified_crossbow_2d: + template: default:model/crossbow_2d + arguments: + model: ${path} + texture: ${path} + arrow_model: ${arrow_path} + arrow_texture: ${arrow_path} + firework_model: ${firework_path} + firework_texture: ${firework_path} + pulling_0_model: ${pulling_0_path} + pulling_0_texture: ${pulling_0_path} + pulling_1_model: ${pulling_1_path} + pulling_1_texture: ${pulling_1_path} + pulling_2_model: ${pulling_2_path} + pulling_2_texture: ${pulling_2_path} \ No newline at end of file diff --git a/common-files/src/main/resources/resources/default/configuration/templates/recipes.yml b/common-files/src/main/resources/resources/default/configuration/templates/recipes.yml new file mode 100644 index 000000000..88dc3bb78 --- /dev/null +++ b/common-files/src/main/resources/resources/default/configuration/templates/recipes.yml @@ -0,0 +1,28 @@ +templates: + # template: default:recipe/planks + # arguments: + # wood_type: the wood type, for instance 'default:palm' + default:recipe/planks: + type: shapeless + category: building + group: planks + ingredients: + - '#${wood_type}_logs' + result: + id: ${wood_type}_planks + count: 4 + # template: default:recipe/log_2_wood + # arguments: + # wood_type: the wood type, for instance 'default:palm' + default:recipe/log_2_wood: + type: shaped + category: building + group: bark + pattern: + - AA + - AA + ingredients: + A: ${wood_type}_log + result: + id: ${wood_type}_wood + count: 3 \ No newline at end of file diff --git a/common-files/src/main/resources/resources/default/configuration/templates/tool_levels.yml b/common-files/src/main/resources/resources/default/configuration/templates/tool_levels.yml new file mode 100644 index 000000000..6478378d3 --- /dev/null +++ b/common-files/src/main/resources/resources/default/configuration/templates/tool_levels.yml @@ -0,0 +1,25 @@ +templates: + default:pickaxe_power/level_1: + - minecraft:wooden_pickaxe + - minecraft:stone_pickaxe + - minecraft:iron_pickaxe + - minecraft:golden_pickaxe + - minecraft:diamond_pickaxe + - minecraft:netherite_pickaxe + - default:topaz_pickaxe + default:pickaxe_power/level_2: + - minecraft:stone_pickaxe + - minecraft:iron_pickaxe + - minecraft:golden_pickaxe + - minecraft:diamond_pickaxe + - minecraft:netherite_pickaxe + - default:topaz_pickaxe + default:pickaxe_power/level_3: + - minecraft:iron_pickaxe + - minecraft:golden_pickaxe + - minecraft:diamond_pickaxe + - minecraft:netherite_pickaxe + - default:topaz_pickaxe + default:pickaxe_power/level_4: + - minecraft:diamond_pickaxe + - minecraft:netherite_pickaxe \ No newline at end of file diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/broken_flame_elytra.png b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/flame_elytra_broken.png similarity index 100% rename from common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/broken_flame_elytra.png rename to common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/flame_elytra_broken.png diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 93b5e5c72..7fa0208a1 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -220,6 +220,8 @@ warning.config.item.legacy_model.missing_path: "Issue found in file Issue found in file - The item '' is missing the require 'path' argument for legacy-model overrides." warning.config.item.legacy_model.overrides.missing_predicate: "Issue found in file - The item '' is missing the require 'predicate' argument for legacy-model overrides." warning.config.item.legacy_model.cannot_convert: "Issue found in file - Cannot convert 1.21.4+ items to legacy format for item ''. Please manually create 'legacy-model' section for this item." +warning.config.item.simplified_model.invalid_model: "Issue found in file - The item '' contains a mismatched number of parameters. The expected number of models is '', but the actual number is ''." +warning.config.item.simplified_model.invalid_texture: "Issue found in file - The item '' contains a mismatched number of parameters. The expected number of textures is '', but the actual number is ''." warning.config.item.model.invalid_type: "Issue found in file - The item '' is using an invalid model type ''." warning.config.item.model.tint.missing_type: "Issue found in file - The item '' is missing the required 'type' argument for tint." warning.config.item.model.tint.invalid_type: "Issue found in file - The item '' is using an invalid tint type ''." @@ -353,6 +355,8 @@ warning.config.block.behavior.attached_stem.missing_facing: "Issue found warning.config.block.behavior.attached_stem.missing_fruit: "Issue found in file - The block '' is missing the required 'fruit' argument for 'attached_stem_block' behavior." warning.config.block.behavior.attached_stem.missing_stem: "Issue found in file - The block '' is missing the required 'stem' argument for 'attached_stem_block' behavior." warning.config.block.behavior.chime.missing_sounds_projectile_hit: "Issue found in file - The block '' is missing the required 'sounds.projectile-hit' argument for 'chime_block' behavior." +warning.config.block.behavior.surface_spreading.missing_base_block: "Issue found in file - The block '' is missing the required 'base-block' argument for 'surface_spreading_block' behavior." +warning.config.block.behavior.snowy.missing_snowy: "Issue found in file - The block '' is missing the required 'snowy' property for 'snowy_block' behavior." warning.config.model.generation.missing_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.invalid_display_position: "Issue found in file - The config '' is using an invalid display position '' in 'generation.display' section. Allowed display positions: []" @@ -477,6 +481,7 @@ warning.config.function.when.missing_source: "Issue found in file Issue found in file - The config '' is missing the required 'rules' argument for 'if_else' function." warning.config.function.update_block_property.missing_properties: "Issue found in file - The config '' is missing the required 'properties' argument for 'update_block_property' function." warning.config.function.transform_block.missing_block: "Issue found in file - The config '' is missing the required 'block' argument for 'transform_block' function." +warning.config.function.cycle_block_property.missing_property: "Issue found in file - The config '' is missing the required 'property' argument for 'cycle_block_property' function." warning.config.selector.missing_type: "Issue found in file - The config '' is missing the required 'type' argument for selector." warning.config.selector.invalid_type: "Issue found in file - The config '' is using an invalid selector type ''." warning.config.selector.invalid_target: "Issue found in file - The config '' is using an invalid selector target ''." diff --git a/common-files/src/main/resources/translations/fr_fr.yml b/common-files/src/main/resources/translations/fr_fr.yml new file mode 100644 index 000000000..49bad7ee0 --- /dev/null +++ b/common-files/src/main/resources/translations/fr_fr.yml @@ -0,0 +1,505 @@ +lang-version: "${lang_version}" + +exception.invalid_syntax: "Syntaxe invalide. Utilisation correcte : " +exception.invalid_argument: "Argument invalide. Raison : " +exception.invalid_sender: " n'est pas autorisé à exécuter cette commande. Doit être de type " +exception.unexpected: "Une erreur interne s'est produite lors de l'exécution de cette commande" +exception.no_permission: "Désolé, mais vous n'avez pas la permission d'utiliser cette commande" +exception.no_such_command: "Commande inconnue." +argument.entity.notfound.player: "" +argument.entity.notfound.entity: "" +argument.parse.failure.time: "'' n'est pas un format de temps valide" +argument.parse.failure.material: "'' n'est pas un nom de matériau valide" +argument.parse.failure.enchantment: "'' n'est pas un enchantement valide" +argument.parse.failure.offlineplayer: "Aucun joueur trouvé pour l'entrée ''" +argument.parse.failure.player: "Aucun joueur trouvé pour l'entrée ''" +argument.parse.failure.world: "'' n'est pas un monde Minecraft valide" +argument.parse.failure.location.invalid_format: "'' n'est pas une position valide. Format requis : ' '" +argument.parse.failure.location.mixed_local_absolute: "Impossible de mélanger coordonnées locales et absolues (soit toutes utilisent '^', soit aucune)" +argument.parse.failure.namespacedkey.namespace: "Espace de noms invalide ''. Doit correspondre à [a-z0-9._-]" +argument.parse.failure.namespacedkey.key: "Clé invalide ''. Doit correspondre à [a-z0-9/._-]" +argument.parse.failure.namespacedkey.need_namespace: "Entrée invalide '', un espace de noms explicite est requis" +argument.parse.failure.boolean: "Impossible d'interpréter un booléen depuis ''" +argument.parse.failure.number: "'' n'est pas un nombre valide dans l’intervalle à " +argument.parse.failure.char: "'' n'est pas un caractère valide" +argument.parse.failure.string: "'' n'est pas une chaîne valide de type " +argument.parse.failure.uuid: "'' n'est pas un UUID valide" +argument.parse.failure.enum: "'' ne fait pas partie des options suivantes : " +argument.parse.failure.regex: "'' ne correspond pas à ''" +argument.parse.failure.flag.unknown: "Indicateur inconnu ''" +argument.parse.failure.flag.duplicate_flag: "Indicateur dupliqué ''" +argument.parse.failure.flag.no_flag_started: "Aucun indicateur commencé. Impossible de traiter ''" +argument.parse.failure.flag.missing_argument: "Argument manquant pour ''" +argument.parse.failure.flag.no_permission: "Vous n'avez pas la permission d'utiliser ''" +argument.parse.failure.color: "'' n'est pas une couleur valide" +argument.parse.failure.duration: "'' n'est pas un format de durée valide" +argument.parse.failure.aggregate.missing: "Composant manquant ''" +argument.parse.failure.aggregate.failure: "Composant invalide '' : " +argument.parse.failure.either: "Impossible de résoudre '' comme ou " +argument.parse.failure.namedtextcolor: "'' n'est pas un nom de couleur de texte valide" +command.reload.config.success: "Configurations rechargées en ms. (Asynchrone : ms | Synchrone : ms)" +command.reload.config.failure: "Échec du rechargement de la configuration. Consultez les logs de la console." +command.reload.pack.success: "Pack de ressources rechargé en ms." +command.reload.pack.failure: "Échec du rechargement du pack de ressources. Consultez les logs de la console." +command.reload.all.success: "Rechargement terminé en ms. (Asynchrone : ms | Synchrone : ms | Pack : ms)" +command.reload.all.failure: "Échec du rechargement. Consultez les logs de la console." +command.item.get.success: "Obtenu de " +command.item.get.failure.not_exist: "'>" +command.item.give.success.single: "':'':''>" +command.item.give.success.multiple: "':'':''>" +command.item.give.failure.not_exist: "'>" +command.search_recipe.not_found: "Aucune recette trouvée pour cet objet" +command.search_usage.not_found: "Aucune utilisation trouvée pour cet objet" +command.search_recipe.no_item: "Veuillez tenir un objet avant d’exécuter cette commande" +command.search_usage.no_item: "Veuillez tenir un objet avant d’exécuter cette commande" +command.totem_animation.failure.not_totem: "L’objet '' n’est pas minecraft:totem_of_undying" +command.totem_animation.success.single: "Animation de totem jouée pour " +command.totem_animation.success.multiple: "Animation de totem jouée pour joueurs" +command.resource.enable.success: "Ressource activée. Exécutez /ce reload all pour appliquer les changements" +command.resource.enable.failure.unknown: "Ressource inconnue " +command.resource.disable.success: "Ressource désactivée. Exécutez /ce reload all pour appliquer les changements" +command.resource.disable.failure.unknown: "Ressource inconnue " +command.resource.list: "Ressources activées(): Ressources désactivées(): " +command.upload.failure.not_supported: "La méthode d’hébergement actuelle '' ne prend pas en charge l’envoi de packs de ressources." +command.upload.on_progress: "Téléversement démarré. Consultez la console pour plus d’informations." +command.send_resource_pack.success.single: "Pack de ressources envoyé à ." +command.send_resource_pack.success.multiple: "Packs de ressources envoyés à joueurs." +command.locale.set.failure: "Format de locale invalide : " +command.locale.set.success: "Locale définie sur pour " +command.locale.unset.success: "Locale réinitialisée pour " +warning.network.resource_pack.unverified_uuid: "Le joueur tente de demander un pack de ressources avec un UUID () qui n’est pas authentifié par le serveur." +warning.config.pack.duplicated_files: "Des fichiers dupliqués ont été trouvés. Veuillez les résoudre via la section 'resource-pack.duplicated-files-handler' dans config.yml." +warning.config.yaml.duplicated_key: "Problème dans le fichier - Clé dupliquée '' détectée à la ligne , cela peut causer des résultats inattendus." +warning.config.yaml.inconsistent_value_type: "Problème dans le fichier - Clé dupliquée '' détectée à la ligne avec des types de valeur différents, cela peut causer des résultats inattendus." +warning.config.type.int: "Problème dans le fichier - Impossible de charger '': Impossible de convertir '' en entier pour l’option ''." +warning.config.type.boolean: "Problème dans le fichier - Impossible de charger '': Impossible de convertir '' en booléen pour l’option ''." +warning.config.type.float: "Problème dans le fichier - Impossible de charger '': Impossible de convertir '' en nombre décimal (float) pour l’option ''." +warning.config.type.double: "Problème dans le fichier - Impossible de charger '': Impossible de convertir '' en double pour l’option ''." +warning.config.type.quaternionf: "Problème dans le fichier - Impossible de charger '': Impossible de convertir '' en Quaternionf pour l’option ''." +warning.config.type.vector3f: "Problème dans le fichier - Impossible de charger '': Impossible de convertir '' en Vector3f pour l’option ''." +warning.config.type.vec3d: "Problème dans le fichier - Impossible de charger '': Impossible de convertir '' en Vec3d pour l’option ''." +warning.config.type.map: "Problème dans le fichier - Impossible de charger '': Impossible de convertir '' en type Map pour l’option ''." +warning.config.type.snbt.invalid_syntax: "Problème dans le fichier - Impossible de charger '': Syntaxe SNBT invalide ''." +warning.config.number.missing_type: "Problème dans le fichier - La configuration '' n’a pas l’argument obligatoire 'type' pour un nombre." +warning.config.number.invalid_type: "Problème dans le fichier - La configuration '' utilise un type de nombre invalide ''." +warning.config.number.missing_argument: "Problème dans le fichier - La configuration '' n’a pas l’argument requis pour 'number'." +warning.config.number.invalid_format: "Problème dans le fichier - La configuration '' utilise un format numérique invalide ''." +warning.config.number.fixed.missing_value: "Problème dans le fichier - La configuration '' n’a pas la valeur requise pour un nombre constant ('value')." +warning.config.number.fixed.invalid_value: "Problème dans le fichier - La configuration '' utilise une valeur invalide '' pour un nombre constant." +warning.config.number.expression.missing_expression: "Problème dans le fichier - La configuration '' n’a pas l’argument requis 'expression' pour un nombre de type expression." +warning.config.number.uniform.missing_min: "Problème dans le fichier - La configuration '' n’a pas l’argument requis 'min' pour un nombre uniforme." +warning.config.number.uniform.missing_max: "Problème dans le fichier - La configuration '' n’a pas l’argument requis 'max' pour un nombre uniforme." +warning.config.number.gaussian.missing_min: "Problème dans le fichier - La configuration '' n’a pas l’argument requis 'min' pour un nombre gaussien." +warning.config.number.gaussian.missing_max: "Problème dans le fichier - La configuration '' n’a pas l’argument requis 'max' pour un nombre gaussien." +warning.config.number.binomial.missing_extra: "Problème dans le fichier - La configuration '' n’a pas l’argument requis 'extra' pour un nombre binomial." +warning.config.number.binomial.missing_probability: "Problème dans le fichier - La configuration '' n’a pas l’argument requis 'probability' pour un nombre binomial." +warning.config.condition.all_of.missing_terms: "Problème dans le fichier - La configuration '' n’a pas l’argument requis 'terms' pour la condition 'all_of'." +warning.config.condition.all_of.invalid_terms_type: "Problème dans le fichier - La condition 'all_of' de '' est mal configurée : 'terms' doit être une liste de maps, type actuel : ''." +warning.config.condition.any_of.missing_terms: "Problème dans le fichier - La configuration '' n’a pas l’argument requis 'terms' pour la condition 'any_of'." +warning.config.condition.any_of.invalid_terms_type: "Problème dans le fichier - La condition 'any_of' de '' est mal configurée : 'terms' doit être une liste de maps, type actuel : ''." +warning.config.condition.inverted.missing_term: "Problème dans le fichier - La configuration '' n’a pas l’argument requis 'term' pour la condition 'inverted'." +warning.config.condition.inverted.invalid_term_type: "Problème dans le fichier - La condition 'inverted' de '' est mal configurée : 'term' doit être une section de configuration, type actuel : ''." +warning.config.condition.enchantment.missing_predicate: "Problème trouvé dans le fichier - La configuration '' manque l'argument obligatoire 'predicate' pour la condition 'enchantment'." +warning.config.condition.enchantment.invalid_predicate: "Problème trouvé dans le fichier - La configuration '' utilise un argument 'predicate' invalide pour l'enchantement ''." +warning.config.condition.match_block_property.missing_properties: "Problème trouvé dans le fichier - La configuration '' manque l'argument obligatoire 'properties' pour la condition 'match_block_property'." +warning.config.condition.match_block.missing_id: "Problème trouvé dans le fichier - La configuration '' manque l'argument obligatoire 'id' pour la condition 'match_block'." +warning.config.condition.match_entity.missing_id: "Problème trouvé dans le fichier - La configuration '' manque l'argument obligatoire 'id' pour la condition 'match_entity'." +warning.config.condition.match_item.missing_id: "Problème trouvé dans le fichier - La configuration '' manque l'argument obligatoire 'id' pour la condition 'match_item'." +warning.config.condition.table_bonus.missing_enchantment: "Problème trouvé dans le fichier - La configuration '' manque l'argument obligatoire 'enchantment' pour la condition 'table_bonus'." +warning.config.condition.table_bonus.missing_chances: "Problème trouvé dans le fichier - La configuration '' manque l'argument obligatoire 'chances' pour la condition 'table_bonus'." +warning.config.condition.permission.missing_permission: "Problème trouvé dans le fichier - La configuration '' manque l'argument obligatoire 'permission' pour la condition 'permission'." +warning.config.condition.string_equals.missing_value1: "Problème trouvé dans le fichier - La configuration '' manque l'argument obligatoire 'value1' pour la condition 'string_equals'." +warning.config.condition.string_equals.missing_value2: "Problème trouvé dans le fichier - La configuration '' manque l'argument obligatoire 'value2' pour la condition 'string_equals'." +warning.config.condition.string_contains.missing_value1: "Problème trouvé dans le fichier - La configuration '' manque l'argument obligatoire 'value1' pour la condition 'string_contains'." +warning.config.condition.string_contains.missing_value2: "Problème trouvé dans le fichier - La configuration '' manque l'argument obligatoire 'value2' pour la condition 'string_contains'." +warning.config.condition.string_regex.missing_value: "Problème trouvé dans le fichier - La configuration '' manque l'argument obligatoire 'value' pour la condition 'string_regex'." +warning.config.condition.string_regex.missing_regex: "Problème trouvé dans le fichier - La configuration '' manque l'argument obligatoire 'regex' pour la condition 'string_regex'." +warning.config.condition.expression.missing_expression: "Problème trouvé dans le fichier - La configuration '' manque l'argument obligatoire 'expression' pour la condition 'expression'." +warning.config.condition.is_null.missing_argument: "Problème trouvé dans le fichier - La configuration '' manque l'argument obligatoire 'argument' pour la condition 'is_null'." +warning.config.condition.hand.missing_hand: "Problème trouvé dans le fichier - La configuration '' manque l'argument obligatoire 'hand' pour la condition 'hand'." +warning.config.condition.hand.invalid_hand: "Problème trouvé dans le fichier - La configuration '' utilise un argument 'hand' invalide '' pour la condition 'hand'. Types de main autorisés : []" +warning.config.condition.on_cooldown.missing_id: "Problème trouvé dans le fichier - La configuration '' manque l'argument obligatoire 'id' pour la condition 'on_cooldown'." +warning.config.structure.not_section: "Problème trouvé dans le fichier - La configuration '' est censée être une section, mais est de type ''." +warning.config.image.duplicate: "Problème trouvé dans le fichier - Image dupliquée ''. Vérifiez s’il y a la même configuration dans d’autres fichiers." +warning.config.image.missing_height: "Problème trouvé dans le fichier - L’image '' manque l’argument obligatoire 'height'." +warning.config.image.height_ascent_conflict: "Problème trouvé dans le fichier - L’image '' viole la règle bitmap : 'height' '' ne doit pas être inférieur à 'ascent' ''." +warning.config.image.missing_file: "Problème trouvé dans le fichier - L’image '' manque l’argument obligatoire 'file'." +warning.config.image.invalid_file_chars: "Problème trouvé dans le fichier - L’image '' a un argument 'file' '' avec des caractères illégaux. Consultez https://minecraft.wiki/w/Resource_location#Legal_characters." +warning.config.image.invalid_font_chars: "Problème trouvé dans le fichier - L’image '' a un argument 'font' '' avec des caractères illégaux. Consultez https://minecraft.wiki/w/Resource_location#Legal_characters." +warning.config.image.invalid_grid_size: "Problème trouvé dans le fichier - L’image '' utilise un format de grille incorrect ''. Exemple correct : '3,5'" +warning.config.image.missing_char: "Problème trouvé dans le fichier - L’image '' manque l’argument obligatoire 'char'." +warning.config.image.codepoint.conflict: "Problème trouvé dans le fichier - L’image '' utilise le caractère '()' déjà utilisé par l’image '' pour la police ." +warning.config.image.codepoint.exhausted: "Problème trouvé dans le fichier - Impossible d’allouer un codepoint pour l’image '' car tous les codepoints sont déjà utilisés pour la police ''." +warning.config.image.invalid_codepoint_grid: "Problème trouvé dans le fichier - L’image '' a une grille de codepoints 'chars' invalide." +warning.config.image.invalid_char: "Problème trouvé dans le fichier - L’image '' contient un caractère combiné, ce qui peut entraîner une séparation de l’image." +warning.config.image.invalid_hex_value: "Problème trouvé dans le fichier - L’image '' utilise le caractère unicode '' qui n’est pas une valeur hexadécimale valide." +warning.config.image.invalid_unicode_string: "Problème trouvé dans le fichier - L’image '' utilise une chaîne unicode incorrecte ''." +warning.config.recipe.duplicate: "Problème trouvé dans le fichier - Recette dupliquée ''. Vérifiez s’il y a la même configuration dans d’autres fichiers." +warning.config.recipe.missing_type: "Problème trouvé dans le fichier - La recette '' manque l’argument obligatoire 'type'." +warning.config.recipe.invalid_type: "Problème trouvé dans le fichier - La recette '' utilise un type de recette invalide ''." +warning.config.recipe.invalid_ingredient: "Problème trouvé dans le fichier - La recette '' utilise un ingrédient invalide ''." +warning.config.recipe.invalid_result: "Problème trouvé dans le fichier - La recette '' utilise un résultat invalide ''." +warning.config.recipe.missing_ingredient: "Problème trouvé dans le fichier - La recette de cuisson '' manque l’argument obligatoire 'ingredient'." +warning.config.recipe.missing_result: "Problème trouvé dans le fichier - La recette '' manque l’argument obligatoire 'result'." +warning.config.recipe.result.missing_id: "Problème trouvé dans le fichier - La recette '' manque l’argument obligatoire 'id' pour le résultat de la recette." +warning.config.recipe.crafting.invalid_category: "Problème trouvé dans le fichier - La recette de crafting '' utilise une catégorie invalide ''. Catégories autorisées : []." +warning.config.recipe.cooking.invalid_category: "Problème trouvé dans le fichier - La recette de cuisson '' utilise une catégorie invalide ''. Catégories autorisées : []." +warning.config.recipe.shaped.missing_pattern: "Problème trouvé dans le fichier - La recette avec forme '' manque l’argument obligatoire 'pattern'." +warning.config.recipe.shaped.invalid_pattern: "Problème trouvé dans le fichier - La recette avec forme '' utilise un motif invalide ''." +warning.config.recipe.shaped.invalid_symbol: "Problème trouvé dans le fichier - La recette avec forme '' utilise un symbole invalide '' dans le motif." +warning.config.recipe.smithing_transform.post_processor.missing_type: "Problème trouvé dans le fichier - La recette de transformation de forge '' manque l’argument obligatoire 'type' pour l’un de ses post-processeurs." +warning.config.recipe.smithing_transform.post_processor.invalid_type: "Problème trouvé dans le fichier - La recette de transformation de forge '' utilise un type de post-processeur invalide ''." +warning.config.recipe.smithing_transform.post_processor.keep_component.missing_components: "Problème trouvé dans le fichier - La recette de transformation de forge '' manque l’argument obligatoire 'components' pour le post-processeur 'keep_components'." +warning.config.recipe.smithing_transform.post_processor.keep_component.missing_tags: "Problème trouvé dans le fichier - La recette de transformation de forge '' manque l’argument obligatoire 'tags' pour le post-processeur 'keep_tags'." +warning.config.recipe.smithing_transform.missing_base: "Problème trouvé dans le fichier - La recette de transformation de forge '' manque l’argument obligatoire 'base'." +warning.config.recipe.smithing_trim.missing_base: "Problème trouvé dans le fichier - La recette de découpe de forge '' manque l’argument obligatoire 'base'." +warning.config.recipe.smithing_trim.missing_template_type: "Problème trouvé dans le fichier - La recette de découpe de forge '' manque l’argument obligatoire 'template-type'." +warning.config.recipe.smithing_trim.missing_addition: "Problème trouvé dans le fichier - La recette de découpe de forge '' manque l’argument obligatoire 'addition'." +warning.config.recipe.smithing_trim.missing_pattern: "Problème trouvé dans le fichier - La recette de découpe de forge '' manque l’argument obligatoire 'pattern'." +warning.config.recipe.brewing.missing_container: "Problème trouvé dans le fichier - La recette de brassage '' manque l’argument obligatoire 'container'." +warning.config.recipe.brewing.missing_ingredient: "Problème trouvé dans le fichier - La recette de brassage '' manque l’argument obligatoire 'ingredient'." +warning.config.recipe.result.post_processor.missing_type: "Problème trouvé dans le fichier - La recette '' manque l’argument obligatoire 'type' pour les post-processeurs de résultat." +warning.config.recipe.result.post_processor.invalid_type: "Problème trouvé dans le fichier - La recette '' utilise un type de post-processeur de résultat invalide ''." +warning.config.translation.unknown_locale: "Problème trouvé dans le fichier - Locale inconnue ''." +warning.config.template.duplicate: "Problème trouvé dans le fichier - Modèle dupliqué ''. Vérifiez s’il existe la même configuration dans d’autres fichiers." +warning.config.template.invalid: "Problème trouvé dans le fichier - La configuration '' utilise un modèle invalide ''." +warning.config.template.argument.self_increase_int.invalid_range: "Problème trouvé dans le fichier - Le modèle '' utilise un 'from' '' supérieur à 'to' '' dans l’argument 'self_increase_int'." +warning.config.template.argument.list.invalid_type: "Problème trouvé dans le fichier - Le modèle '' utilise un argument 'list' qui attend une 'List', mais le type fourni est ''." +warning.config.template.argument.missing_value: "Problème trouvé dans le fichier - La configuration '' manque la valeur de l’argument de modèle ''. Utilisez l’option 'arguments' pour définir une valeur par défaut." +warning.config.vanilla_loot.missing_type: "Problème trouvé dans le fichier - Le loot vanilla '' manque l’argument obligatoire 'type'." +warning.config.vanilla_loot.invalid_type: "Problème trouvé dans le fichier - Le loot vanilla '' utilise un type invalide ''. Types autorisés : []." +warning.config.vanilla_loot.block.invalid_target: "Problème trouvé dans le fichier - Cible de bloc invalide '' dans le loot vanilla ''." +warning.config.sound.duplicate: "Problème trouvé dans le fichier - Son dupliqué ''. Vérifiez s’il existe la même configuration dans d’autres fichiers." +warning.config.sound.missing_sounds: "Problème trouvé dans le fichier - Le son '' manque l’argument obligatoire 'sounds'." +warning.config.sound.missing_name: "Problème trouvé dans le fichier - Le son '' manque l’argument obligatoire 'name'." +warning.config.jukebox_song.duplicate: "Problème trouvé dans le fichier - Chanson de jukebox dupliquée ''. Vérifiez s’il existe la même configuration dans d’autres fichiers." +warning.config.jukebox_song.missing_sound: "Problème trouvé dans le fichier - La chanson de jukebox '' manque l’argument obligatoire 'sound'." +warning.config.furniture.duplicate: "Problème trouvé dans le fichier - Meuble dupliqué ''. Vérifiez s’il existe la même configuration dans d’autres fichiers." +warning.config.furniture.missing_placement: "Problème trouvé dans le fichier - Le meuble '' manque l’argument obligatoire 'placement'." +warning.config.furniture.element.missing_item: "Problème trouvé dans le fichier - Le meuble '' manque l’argument obligatoire 'item' pour un de ses éléments." +warning.config.furniture.settings.unknown: "Problème trouvé dans le fichier - Le meuble '' utilise un type de paramètre inconnu ''." +warning.config.furniture.hitbox.invalid_type: "Problème trouvé dans le fichier - Le meuble '' utilise un type de hitbox invalide ''." +warning.config.furniture.hitbox.custom.invalid_entity: "Problème trouvé dans le fichier - Le meuble '' utilise un hitbox personnalisé avec un type d’entité invalide ''." +warning.config.item.duplicate: "Problème trouvé dans le fichier - Objet dupliqué ''. Vérifiez s’il existe la même configuration dans d’autres fichiers." +warning.config.item.settings.unknown: "Problème trouvé dans le fichier - L’objet '' utilise un type de paramètre inconnu ''." +warning.config.item.settings.invulnerable.invalid_damage_source: "Problème trouvé dans le fichier - L’objet '' utilise une source de dégâts inconnue ''. Sources autorisées : []." +warning.config.item.settings.equipment.missing_asset_id: "Problème trouvé dans le fichier - L’objet '' manque l’argument obligatoire 'asset-id' pour le paramètre 'equipment'." +warning.config.item.settings.equipment.invalid_asset_id: "Problème trouvé dans le fichier - L’objet '' utilise un 'asset-id' invalide pour le paramètre 'equipment'. Il se peut que la configuration de l’équipement n’existe pas ou que l’ID soit mal orthographié." +warning.config.item.settings.projectile.missing_item: "Problème trouvé dans le fichier - L’objet '' manque l’argument obligatoire 'item' pour le paramètre 'projectile'." +warning.config.item.settings.craft_remainder.missing_type: "Problème trouvé dans le fichier - L’objet '' manque l’argument obligatoire 'type' pour 'craft-remainder'." +warning.config.item.settings.craft_remainder.invalid_type: "Problème trouvé dans le fichier - L’objet '' utilise un type de 'craft-remainder' invalide ''." +warning.config.item.settings.craft_remainder.fixed.missing_item: "Problème trouvé dans le fichier - L’objet '' manque l’argument obligatoire 'item' pour un 'craft-remainder' fixe." +warning.config.item.settings.craft_remainder.recipe_based.missing_terms: "Problème trouvé dans le fichier - L’objet '' manque l’argument obligatoire 'terms' pour un 'craft-remainder' basé sur une recette." +warning.config.item.data.attribute_modifiers.missing_type: "Problème trouvé dans le fichier - L’objet '' manque l’argument obligatoire 'type' pour les données 'attribute-modifiers'." +warning.config.item.data.attribute_modifiers.missing_amount: "Problème trouvé dans le fichier - L’objet '' manque l’argument obligatoire 'amount' pour les données 'attribute-modifiers'." +warning.config.item.data.attribute_modifiers.missing_operation: "Problème trouvé dans le fichier - L’objet '' manque l’argument obligatoire 'operation' pour les données 'attribute-modifiers'." +warning.config.item.data.attribute_modifiers.display.missing_type: "Problème trouvé dans le fichier - L’objet '' manque l’argument obligatoire 'type' pour les données d’affichage 'attribute-modifiers'." +warning.config.item.data.attribute_modifiers.display.missing_value: "Problème trouvé dans le fichier - L’objet '' manque l’argument obligatoire 'value' pour les données d’affichage 'attribute-modifiers'." +warning.config.item.data.external.missing_source: "Problème trouvé dans le fichier - L’objet '' manque l’argument obligatoire 'source' pour les données 'external'." +warning.config.item.data.external.missing_id: "Problème trouvé dans le fichier - L’objet '' manque l’argument obligatoire 'id' pour les données 'external'." +warning.config.item.data.external.invalid_source: "Problème trouvé dans le fichier - L’objet '' utilise une source de données 'external' invalide ''." +warning.config.item.missing_material: "Problème trouvé dans le fichier - L’objet '' manque l’argument obligatoire 'material'." +warning.config.item.invalid_material: "Problème trouvé dans le fichier - L’objet '' utilise un type de matériau invalide ''." +warning.config.item.invalid_custom_model_data: "Problème trouvé dans le fichier - L’objet '' utilise des données de modèle personnalisées négatives '', ce qui est invalide." +warning.config.item.bad_custom_model_data: "Problème trouvé dans le fichier - L’objet '' utilise des données de modèle personnalisées trop grandes ''. Il est recommandé d’utiliser une valeur inférieure à 16 777 216." +warning.config.item.item_model.conflict: "Problème trouvé dans le fichier - L’objet '' utilise une option 'item-model' invalide car ce modèle est déjà utilisé par un objet vanilla." +warning.config.item.custom_model_data.conflict: "Problème trouvé dans le fichier - L’objet '' utilise des données de modèle personnalisées '' déjà attribuées à l’objet ''." +warning.config.item.custom_model_data.exhausted: "Problème trouvé dans le fichier - Impossible d’allouer des données de modèle personnalisées pour l’objet '' car toutes les données disponibles pour le matériau '' sont épuisées." +warning.config.item.invalid_component: "Problème trouvé dans le fichier - L’objet '' utilise un type de composant inexistant ''." +warning.config.item.missing_model_id: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'custom-model-data' ou 'item-model'." +warning.config.item.missing_model: "Problème trouvé dans le fichier - L’objet '' manque la section 'model' requise pour la compatibilité avec les packs de ressources 1.21.4+." +warning.config.item.behavior.missing_type: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'type' pour son comportement." +warning.config.item.behavior.invalid_type: "Problème trouvé dans le fichier - L’objet '' utilise un type de comportement invalide ''." +warning.config.item.behavior.block.missing_block: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'block' pour le comportement 'block_item'." +warning.config.item.behavior.wall_block.missing_block: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'block' pour le comportement 'wall_block_item'." +warning.config.item.behavior.furniture.missing_furniture: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'furniture' pour le comportement 'furniture_item'." +warning.config.item.behavior.liquid_collision.missing_block: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'block' pour le comportement 'liquid_collision_block_item'." +warning.config.item.behavior.double_high.missing_block: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'block' pour le comportement 'double_high_block_item'." +warning.config.item.legacy_model.missing_path: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'path' pour le modèle legacy." +warning.config.item.legacy_model.overrides.missing_path: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'path' pour les overrides du modèle legacy." +warning.config.item.legacy_model.overrides.missing_predicate: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'predicate' pour les overrides du modèle legacy." +warning.config.item.legacy_model.cannot_convert: "Problème trouvé dans le fichier - Impossible de convertir les objets 1.21.4+ au format legacy pour l’objet ''. Veuillez créer manuellement la section 'legacy-model'." +warning.config.item.model.invalid_type: "Problème trouvé dans le fichier - L’objet '' utilise un type de modèle invalide ''." +warning.config.item.model.tint.missing_type: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'type' pour le tint." +warning.config.item.model.tint.invalid_type: "Problème trouvé dans le fichier - L’objet '' utilise un type de tint invalide ''." +warning.config.item.model.tint.constant.missing_value: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'value' pour le tint constant." +warning.config.item.model.tint.grass.invalid_temp: "Problème trouvé dans le fichier - L’objet '' utilise une température invalide '' pour le tint de l’herbe (valeurs attendues entre 0 et 1)." +warning.config.item.model.tint.grass.invalid_downfall: "Problème trouvé dans le fichier - L’objet '' utilise une précipitation invalide '' pour le tint de l’herbe (valeurs attendues entre 0 et 1)." +warning.config.item.model.tint.invalid_value: "Problème trouvé dans le fichier - L’objet '' utilise un tint invalide ''." +warning.config.item.model.base.missing_path: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'path' pour le modèle 'minecraft:model'." +warning.config.item.model.base.invalid_path: "Problème trouvé dans le fichier - L’objet '' a un 'path' invalide '' contenant des caractères interdits. Voir https://minecraft.wiki/w/Resource_location#Legal_characters." +warning.config.item.model.condition.missing_property: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'property' pour le modèle 'minecraft:condition'." +warning.config.item.model.condition.invalid_property: "Problème trouvé dans le fichier - L’objet '' utilise une propriété invalide '' pour le modèle 'minecraft:condition'." +warning.config.item.model.condition.missing_on_true: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'on-true' pour le modèle 'minecraft:condition'." +warning.config.item.model.condition.missing_on_false: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'on-false' pour le modèle 'minecraft:condition'." +warning.config.item.model.condition.keybind.missing_keybind: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'keybind' pour la propriété 'minecraft:keybind_down'." +warning.config.item.model.condition.has_component.missing_component: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'component' pour la propriété 'minecraft:has_component'." +warning.config.item.model.condition.component.missing_predicate: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'predicate' pour la propriété 'minecraft:component'." +warning.config.item.model.condition.component.missing_value: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'value' pour la propriété 'minecraft:component'." +warning.config.item.model.composite.missing_models: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'models' pour le modèle 'minecraft:composite'." +warning.config.item.model.range_dispatch.missing_property: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'property' pour le modèle 'minecraft:range_dispatch'." +warning.config.item.model.range_dispatch.invalid_property: "Problème trouvé dans le fichier - L’objet '' utilise une propriété invalide '' pour le modèle 'minecraft:range_dispatch'." +warning.config.item.model.range_dispatch.missing_entries: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'entries' pour le modèle 'minecraft:composite'." +warning.config.item.model.range_dispatch.entry.missing_model: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'model' pour l’une des entrées du modèle 'minecraft:composite'." +warning.config.item.model.range_dispatch.compass.missing_target: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'target' pour la propriété 'minecraft:compass'." +warning.config.item.model.range_dispatch.time.missing_source: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'source' pour la propriété 'minecraft:time'." +warning.config.item.model.select.missing_property: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'property' pour le modèle 'minecraft:select'." +warning.config.item.model.select.invalid_property: "Problème trouvé dans le fichier - L’objet '' utilise une propriété invalide '' pour le modèle 'minecraft:select'." +warning.config.item.model.select.missing_cases: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'cases' pour le modèle 'minecraft:select'." +warning.config.item.model.select.case.missing_when: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'when' pour l’un des cas du modèle 'minecraft:select'." +warning.config.item.model.select.case.missing_model: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'model' pour l’un des cas du modèle 'minecraft:select'." +warning.config.item.model.select.block_state.missing_property: "Problème trouvé dans le fichier - L’objet '' manque l’argument requis 'block-state-property' pour la propriété 'minecraft:block_state'." +warning.config.item.model.select.local_time.missing_pattern: "Problème trouvé dans le fichier - L'objet '' manque l'argument requis 'pattern' pour la propriété 'minecraft:local_time'." +warning.config.item.model.select.component.missing_component: "Problème trouvé dans le fichier - L'objet '' manque l'argument requis 'component' pour la propriété 'minecraft:component'." +warning.config.item.model.special.missing_type: "Problème trouvé dans le fichier - L'objet '' manque l'argument requis 'type' pour le modèle 'minecraft:special'." +warning.config.item.model.special.missing_path: "Problème trouvé dans le fichier - L'objet '' manque l'argument requis 'path' pour le modèle 'minecraft:special'." +warning.config.item.model.special.invalid_path: "Problème trouvé dans le fichier - L'objet '' utilise un argument 'path' invalide '' pour le modèle 'minecraft:special' contenant des caractères interdits. Veuillez lire https://minecraft.wiki/w/Resource_location#Legal_characters." +warning.config.item.model.special.invalid_type: "Problème trouvé dans le fichier - L'objet '' utilise un type invalide '' pour le modèle 'minecraft:special'." +warning.config.item.model.special.banner.missing_color: "Problème trouvé dans le fichier - L'objet '' manque l'argument requis 'color' pour le modèle spécial 'minecraft:banner'." +warning.config.item.model.special.bed.missing_texture: "Problème trouvé dans le fichier - L'objet '' manque l'argument requis 'texture' pour le modèle spécial 'minecraft:bed'." +warning.config.item.model.special.sign.missing_wood_type: "Problème trouvé dans le fichier - L'objet '' manque l'argument requis 'wood-type' pour le modèle spécial 'minecraft:hanging_sign'/'minecraft:standing_sign'." +warning.config.item.model.special.sign.missing_texture: "Problème trouvé dans le fichier - L'objet '' manque l'argument requis 'texture' pour le modèle spécial 'minecraft:hanging_sign'/'minecraft:standing_sign'." +warning.config.item.model.special.chest.missing_texture: "Problème trouvé dans le fichier - L'objet '' manque l'argument requis 'texture' pour le modèle spécial 'minecraft:chest'." +warning.config.item.model.special.chest.invalid_openness: "Problème trouvé dans le fichier - L'objet '' utilise une valeur 'openness' invalide '' pour le modèle spécial 'minecraft:chest'. Plage valide '0~1'." +warning.config.item.model.special.shulker_box.missing_texture: "Problème trouvé dans le fichier - L'objet '' manque l'argument requis 'texture' pour le modèle spécial 'minecraft:shulker_box'." +warning.config.item.model.special.shulker_box.invalid_openness: "Problème trouvé dans le fichier - L'objet '' utilise une valeur 'openness' invalide '' pour le modèle spécial 'minecraft:shulker_box'. Plage valide '0~1'." +warning.config.item.model.special.head.missing_kind: "Problème trouvé dans le fichier - L'objet '' manque l'argument requis 'kind' pour le modèle spécial 'minecraft:head'." +warning.config.item.model.special.copper_golem_statue.missing_pose: "Problème trouvé dans le fichier - L'objet '' manque l'argument requis 'pose' pour le modèle spécial 'minecraft:copper_golem_statue'." +warning.config.item.model.special.copper_golem_statue.missing_texture: "Problème trouvé dans le fichier - L'objet '' manque l'argument requis 'texture' pour le modèle spécial 'minecraft:copper_golem_statue'." +warning.config.item.updater.missing_type: "Problème trouvé dans le fichier - L'objet '' manque l'argument requis 'type' pour le mise à jour d'objet." +warning.config.item.updater.invalid_type: "Problème trouvé dans le fichier - L'objet '' utilise un argument 'type' invalide '' pour le mise à jour d'objet." +warning.config.item.updater.transmute.missing_material: "Problème trouvé dans le fichier - L'objet '' manque l'argument requis 'material' pour la mise à jour d'objet 'transmute'." +warning.config.block_state_mapping.invalid_state: "Problème trouvé dans le fichier - La configuration '' utilise un état de bloc invalide ''." +warning.config.block_state_mapping.conflict: "Problème trouvé dans le fichier - La configuration '' ne peut pas mapper l'état de bloc à car il a déjà été mappé à ." +warning.config.block.duplicate: "Problème trouvé dans le fichier - Bloc dupliqué ''. Vérifiez si la même configuration existe dans d'autres fichiers." +warning.config.block.missing_state: "Problème trouvé dans le fichier - Le bloc '' manque l'argument requis 'state'." +warning.config.block.state.property.missing_type: "Problème trouvé dans le fichier - Le bloc '' manque l'argument requis 'type' pour la propriété ''." +warning.config.block.state.property.invalid_type: "Problème trouvé dans le fichier - Le bloc '' utilise un argument 'type' invalide '' pour la propriété ''." +warning.config.block.state.property.integer.invalid_range: "Problème trouvé dans le fichier - Le bloc '' utilise un argument 'range' invalide '' pour la propriété entière ''. Syntaxe correcte: 1~2." +warning.config.block.state.property.invalid_format: "Problème trouvé dans le fichier - Le bloc '' utilise un format de propriété d'état de bloc invalide ''." +warning.config.block.state.missing_state: "Problème trouvé dans le fichier - Le bloc '' manque l'argument requis 'state' pour 'state'." +warning.config.block.state.missing_properties: "Problème trouvé dans le fichier - Le bloc '' manque la section requise 'properties' pour 'states'." +warning.config.block.state.missing_appearances: "Problème trouvé dans le fichier - Le bloc '' manque la section requise 'appearances' pour 'states'." +warning.config.block.state.entity_renderer.invalid_type: "Problème trouvé dans le fichier - Le bloc '' utilise un type de renderer d'entité invalide ''." +warning.config.block.state.entity_renderer.item_display.missing_item: "Problème trouvé dans le fichier - Le bloc '' manque l'argument requis 'item' pour le renderer d'entité 'item_display'." +warning.config.block.state.entity_renderer.text_display.missing_text: "Problème trouvé dans le fichier - Le bloc '' manque l'argument requis 'text' pour le renderer d'entité 'text_display'." +warning.config.block.state.entity_renderer.better_model.missing_model: "Problème trouvé dans le fichier - Le bloc '' manque l'argument requis 'model' pour le renderer d'entité 'better_model'." +warning.config.block.state.entity_renderer.model_engine.missing_model: "Problème trouvé dans le fichier - Le bloc '' manque l'argument requis 'model' pour le renderer d'entité 'model_engine'." +warning.config.block.state.variant.invalid_appearance: "Problème trouvé dans le fichier - Le bloc '' a une erreur: la variante '' utilise une apparence inexistante ''." +warning.config.block.state.invalid_vanilla: "Problème trouvé dans le fichier - Le bloc '' utilise un état de bloc vanilla invalide ''." +warning.config.block.state.invalid_auto_state: "Problème trouvé dans le fichier - Le bloc '' utilise un auto-état invalide ''. Valeurs autorisées: []." +warning.config.block.state.auto_state.exhausted: "Problème trouvé dans le fichier - Le groupe d'état visuel '' a atteint sa capacité maximale de '' slots et ne peut pas allouer d'état pour le bloc ''." +warning.config.block.state.unavailable_vanilla: "Problème trouvé dans le fichier - Le bloc '' utilise un état de bloc vanilla non disponible ''. Veuillez libérer cet état dans block-state-mappings." +warning.config.block.state.invalid_vanilla_id: "Problème trouvé dans le fichier - Le bloc '' utilise un état de bloc vanilla '' qui dépasse la plage de slots disponible '0~'." +warning.config.block.state.invalid_id: "Problème trouvé dans le fichier - La plage ID de l'état de bloc () utilisée par le bloc '' est hors de la plage valide 0 à . Veuillez ajouter plus de blocs côté serveur dans 'config.yml' si les slots actuels sont épuisés." +warning.config.block.state.id.conflict: "Problème trouvé dans le fichier - Le bloc '' n'a pas pu lier l'état réel pour '' car il est occupé par ''." +warning.config.block.state.id.exhausted: "Problème trouvé dans le fichier - Impossible d'allouer suffisamment d'état réel pour le bloc ''. Ajoutez plus de blocs côté serveur dans 'config.yml' et redémarrez si les slots actuels sont épuisés." +warning.config.block.state.model.missing_path: "Problème trouvé dans le fichier - Le bloc '' manque l'option requise 'path' pour 'model'." +warning.config.block.state.model.invalid_path: "Problème trouvé dans le fichier - Le bloc '' a un argument 'path' '' contenant des caractères interdits. Veuillez lire https://minecraft.wiki/w/Resource_location#Legal_characters" +warning.config.block.state.model.conflict: "Problème trouvé dans le fichier - Le bloc '' essaie de lier le modèle '' à l'état '' déjà lié au modèle ''." +warning.config.block.settings.unknown: "Problème trouvé dans le fichier - Le bloc '' utilise un type de configuration inconnu ''." +warning.config.block.behavior.missing_type: "Problème trouvé dans le fichier - Le bloc '' manque l'argument requis 'type' pour le comportement du bloc." +warning.config.block.behavior.concrete.missing_solid: "Problème trouvé dans le fichier - Le bloc '' manque de l'option requise 'solid-block' pour le comportement 'concrete_block'." +warning.config.block.behavior.crop.missing_age: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'age' pour le comportement 'crop_block'." +warning.config.block.behavior.vertical_crop.missing_age: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'age' pour le comportement 'vertical_crop_block'." +warning.config.block.behavior.leaves.missing_persistent: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'persistent' pour le comportement 'leaves_block'." +warning.config.block.behavior.leaves.missing_distance: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'distance' pour le comportement 'leaves_block'." +warning.config.block.behavior.lamp.missing_lit: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'lit' pour le comportement 'lamp_block'." +warning.config.block.behavior.toggleable_lamp.missing_lit: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'lit' pour le comportement 'toggleable_lamp_block'." +warning.config.block.behavior.toggleable_lamp.missing_powered: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'powered' pour le comportement 'toggleable_lamp_block'." +warning.config.block.behavior.door.missing_half: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'half' pour le comportement 'door_block'." +warning.config.block.behavior.door.missing_facing: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'facing' pour le comportement 'door_block'." +warning.config.block.behavior.door.missing_hinge: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'hinge' pour le comportement 'door_block'." +warning.config.block.behavior.door.missing_open: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'open' pour le comportement 'door_block'." +warning.config.block.behavior.door.missing_powered: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'powered' pour le comportement 'door_block'." +warning.config.block.behavior.trapdoor.missing_half: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'half' pour le comportement 'trapdoor_block'." +warning.config.block.behavior.trapdoor.missing_facing: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'facing' pour le comportement 'trapdoor_block'." +warning.config.block.behavior.trapdoor.missing_open: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'open' pour le comportement 'trapdoor_block'." +warning.config.block.behavior.trapdoor.missing_powered: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'powered' pour le comportement 'trapdoor_block'." +warning.config.block.behavior.stackable.missing_property: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise '' pour le comportement 'stackable_block'." +warning.config.block.behavior.stackable.missing_items: "Problème trouvé dans le fichier - Le bloc '' manque de l'argument requis 'items' pour le comportement 'stackable_block'." +warning.config.block.behavior.fence_gate.missing_facing: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'facing' pour le comportement 'fence_gate_block'." +warning.config.block.behavior.fence_gate.missing_in_wall: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'in_wall' pour le comportement 'fence_gate_block'." +warning.config.block.behavior.fence_gate.missing_open: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'open' pour le comportement 'fence_gate_block'." +warning.config.block.behavior.fence_gate.missing_powered: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'powered' pour le comportement 'fence_gate_block'." +warning.config.block.behavior.slab.missing_type: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'type' pour le comportement 'slab_block'." +warning.config.block.behavior.stairs.missing_facing: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'facing' pour le comportement 'stairs_block'." +warning.config.block.behavior.stairs.missing_half: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'half' pour le comportement 'stairs_block'." +warning.config.block.behavior.stairs.missing_shape: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'shape' pour le comportement 'stairs_block'." +warning.config.block.behavior.sofa.missing_facing: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'facing' pour le comportement 'sofa_block'." +warning.config.block.behavior.sofa.missing_shape: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'shape' pour le comportement 'sofa_block'." +warning.config.block.behavior.pressure_plate.missing_powered: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'powered' pour le comportement 'pressure_plate_block'." +warning.config.block.behavior.grass.missing_feature: "Problème trouvé dans le fichier - Le bloc '' manque de l'argument requis 'feature' pour le comportement 'grass_block'." +warning.config.block.behavior.double_high.missing_half: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'half' pour le comportement 'double_block'." +warning.config.block.behavior.change_over_time.missing_next_block: "Problème trouvé dans le fichier - Le bloc '' manque de l'argument requis 'next_block' pour le comportement 'change_over_time_block'." +warning.config.block.behavior.directional_attached.missing_facing: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'facing' pour le comportement 'directional_attached_block'." +warning.config.block.behavior.wall_torch_particle.missing_facing: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'facing' pour le comportement 'wall_torch_particle_block'." +warning.config.block.behavior.fence.missing_north: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'north' pour le comportement 'fence_block'." +warning.config.block.behavior.fence.missing_east: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'east' pour le comportement 'fence_block'." +warning.config.block.behavior.fence.missing_south: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'south' pour le comportement 'fence_block'." +warning.config.block.behavior.fence.missing_west: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'west' pour le comportement 'fence_block'." +warning.config.block.behavior.face_attached_horizontal_directional.missing_face: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'face' pour le comportement 'face_attached_horizontal_directional_block'." +warning.config.block.behavior.face_attached_horizontal_directional.missing_facing: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'facing' pour le comportement 'face_attached_horizontal_directional_block'." +warning.config.block.behavior.button.missing_powered: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'powered' pour le comportement 'button_block'." +warning.config.block.behavior.stem.missing_age: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'age' pour le comportement 'stem_block'." +warning.config.block.behavior.stem.missing_fruit: "Problème trouvé dans le fichier - Le bloc '' manque de l'argument requis 'fruit' pour le comportement 'stem_block'." +warning.config.block.behavior.stem.missing_attached_stem: "Problème trouvé dans le fichier - Le bloc '' manque de l'argument requis 'attached_stem' pour le comportement 'stem_block'." +warning.config.block.behavior.attached_stem.missing_facing: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'facing' pour le comportement 'attached_stem_block'." +warning.config.block.behavior.attached_stem.missing_fruit: "Problème trouvé dans le fichier - Le bloc '' manque de l'argument requis 'fruit' pour le comportement 'attached_stem_block'." +warning.config.block.behavior.attached_stem.missing_stem: "Problème trouvé dans le fichier - Le bloc '' manque de l'argument requis 'stem' pour le comportement 'attached_stem_block'." +warning.config.block.behavior.chime.missing_sounds_projectile_hit: "Problème trouvé dans le fichier - Le bloc '' manque de l'argument requis 'sounds.projectile-hit' pour le comportement 'chime_block'." +warning.config.block.behavior.surface_spreading.missing_base_block: "Problème trouvé dans le fichier - Le bloc '' manque de l'argument requis 'base-block' pour le comportement 'surface_spreading_block'." +warning.config.block.behavior.snowy.missing_snowy: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'snowy' pour le comportement 'snowy_block'." +warning.config.block.behavior.sapling.missing_stage: "Problème trouvé dans le fichier - Le bloc '' manque de la propriété requise 'stage' pour le comportement 'sapling_block'." +warning.config.block.behavior.sapling.missing_feature: "Problème trouvé dans le fichier - Le bloc '' manque de l'argument requis 'feature' pour le comportement 'sapling_block'." +warning.config.block.behavior.strippable.missing_stripped: "Problème trouvé dans le fichier - Le bloc '' manque de l'argument requis 'stripped' pour le comportement 'strippable_block'." +warning.config.block.behavior.invalid_type: "Problème trouvé dans le fichier - Le bloc '' utilise un type de comportement de bloc invalide ''." +warning.config.model.generation.missing_parent: "Problème trouvé dans le fichier - La configuration '' manque de l'argument requis 'parent' dans la section 'generation'." +warning.config.model.generation.conflict: "Problème trouvé dans le fichier - Impossible de générer le modèle pour '' car deux configurations ou plus essaient de générer des modèles JSON différents avec le même chemin : ''." +warning.config.model.generation.invalid_display_position: "Problème trouvé dans le fichier - La configuration '' utilise une position d'affichage invalide '' dans la section 'generation.display'. Positions autorisées : []" +warning.config.model.generation.invalid_gui_light: "Problème trouvé dans le fichier - La configuration '' utilise une option gui-light invalide '' dans la section 'generation'. Options autorisées : []" +warning.config.model.generation.texture.invalid: "Problème trouvé dans le fichier - La configuration '' a une texture '' avec le chemin '' contenant des caractères interdits. Veuillez lire https://minecraft.wiki/w/Resource_location#Legal_characters." +warning.config.model.generation.parent.invalid: "Problème trouvé dans le fichier - La configuration '' a un argument parent '' contenant des caractères interdits. Veuillez lire https://minecraft.wiki/w/Resource_location#Legal_characters." +warning.config.emoji.missing_keywords: "Problème trouvé dans le fichier - L'emoji '' manque de l'argument requis 'keywords'." +warning.config.emoji.duplicate: "Problème trouvé dans le fichier - Emoji dupliqué ''. Vérifiez si la même configuration existe dans d'autres fichiers." +warning.config.emoji.invalid_image: "Problème trouvé dans le fichier - L'emoji '' utilise un argument 'image' invalide ''." +warning.config.advancement.duplicate: "Problème trouvé dans le fichier - Avancement dupliqué ''. Vérifiez si la même configuration existe dans d'autres fichiers." +warning.config.loot_table.missing_pools: "Problème trouvé dans le fichier - '' a une table de butin mal configurée qui manque de l'argument requis 'pools'." +warning.config.loot_table.invalid_pools_type: "Problème trouvé dans le fichier - '' a une table de butin mal configurée, 'pools' doit être une liste de maps/arrays, type actuel : ''." +warning.config.loot_table.invalid_conditions_type: "Problème trouvé dans le fichier - '' a une table de butin mal configurée, 'conditions' doit être une liste de maps, type actuel : ''." +warning.config.loot_table.invalid_functions_type: "Problème trouvé dans le fichier - '' a une table de butin mal configurée, 'functions' doit être une liste de maps, type actuel : ''." +warning.config.loot_table.invalid_entries_type: "Problème trouvé dans le fichier - '' a une table de butin mal configurée, 'entries' doit être une liste de maps, type actuel : ''." +warning.config.loot_table.function.missing_type: "Problème trouvé dans le fichier - '' a une table de butin mal configurée, une des fonctions manque de l'argument requis 'type'." +warning.config.loot_table.function.invalid_type: "Problème trouvé dans le fichier - '' a une table de butin mal configurée, une des fonctions utilise un type de fonction invalide ''." +warning.config.loot_table.function.apply_bonus.missing_enchantment: "Problème trouvé dans le fichier - '' a une table de butin mal configurée, la fonction 'apply_bonus' manque de l'argument requis 'enchantment'." +warning.config.loot_table.function.apply_bonus.missing_formula: "Problème trouvé dans le fichier - '' a une table de butin mal configurée, la fonction 'apply_bonus' manque de l'argument requis 'formula'." +warning.config.loot_table.function.drop_exp.missing_count: "Problème trouvé dans le fichier - '' a une table de butin mal configurée, la fonction 'drop_exp' manque de l'argument requis 'count'." +warning.config.loot_table.function.set_count.missing_count: "Problème trouvé dans le fichier - '' a une table de butin mal configurée, la fonction 'set_count' manque de l'argument requis 'count'." +warning.config.loot_table.function.apply_data.missing_data: "Problème trouvé dans le fichier - '' a une table de butin mal configurée, la fonction 'apply_data' manque de l'argument requis 'data'." +warning.config.loot_table.entry.missing_type: "Problème trouvé dans le fichier - '' a une table de butin mal configurée, une des entrées manque de l'argument requis 'type'." +warning.config.loot_table.entry.invalid_type: "Problème trouvé dans le fichier - '' a une table de butin mal configurée, une des entrées utilise un type invalide ''." +warning.config.loot_table.entry.exp.missing_count: "Problème trouvé dans le fichier - '' a une table de butin mal configurée, l'entrée 'exp' manque de l'argument requis 'count'." +warning.config.loot_table.entry.item.missing_item: "Problème trouvé dans le fichier - '' a une table de butin mal configurée, l'entrée 'item' manque de l'argument requis 'item'." +warning.config.loot_table.condition.missing_type: "Problème trouvé dans le fichier - '' a une table de butin mal configurée, une des conditions manque de l'argument requis 'type'." +warning.config.loot_table.condition.invalid_type: "Problème trouvé dans le fichier - '' a une table de butin mal configurée, une des conditions utilise un type invalide ''." +warning.config.host.missing_type: "Problème trouvé dans config.yml à 'resource-pack.delivery.hosting' - L'argument requis 'type' est manquant pour l'hôte." +warning.config.host.invalid_type: "Problème trouvé dans config.yml à 'resource-pack.delivery.hosting' - Le type d'hôte '' est invalide. Veuillez lire https://xiao-momi.github.io/craft-engine-wiki/getting_start/set_up_host" +warning.config.host.external.missing_url: "Problème trouvé dans config.yml à 'resource-pack.delivery.hosting' - L'argument requis 'url' est manquant pour l'hôte externe." +warning.config.host.alist.missing_api_url: "Problème trouvé dans config.yml à 'resource-pack.delivery.hosting' - L'argument requis 'api-url' est manquant pour l'hôte alist." +warning.config.host.alist.missing_username: "Problème trouvé dans config.yml à 'resource-pack.delivery.hosting' - L'argument requis 'username' ou la variable d'environnement 'CE_ALIST_USERNAME' est manquant pour l'hôte alist." +warning.config.host.alist.missing_password: "Problème trouvé dans config.yml à 'resource-pack.delivery.hosting' - L'argument requis 'password' ou la variable d'environnement 'CE_ALIST_PASSWORD' est manquant pour l'hôte alist." +warning.config.host.alist.missing_upload_path: "Problème trouvé dans config.yml à 'resource-pack.delivery.hosting' - L'argument requis 'upload-path' est manquant pour l'hôte alist." +warning.config.host.dropbox.missing_app_key: "Problème trouvé dans config.yml à 'resource-pack.delivery.hosting' - L'argument requis 'app-key' ou la variable d'environnement 'CE_DROPBOX_APP_KEY' est manquant pour l'hôte dropbox." +warning.config.host.dropbox.missing_app_secret: "Problème trouvé dans config.yml à 'resource-pack.delivery.hosting' - L'argument requis 'app-secret' ou la variable d'environnement 'CE_DROPBOX_APP_SECRET' est manquant pour l'hôte dropbox." +warning.config.host.dropbox.missing_refresh_token: "Problème trouvé dans config.yml à 'resource-pack.delivery.hosting' - L'argument requis 'refresh-token' ou la variable d'environnement 'CE_DROPBOX_REFRESH_TOKEN' est manquant pour l'hôte dropbox." +warning.config.host.dropbox.missing_upload_path: "Problème trouvé dans config.yml à 'resource-pack.delivery.hosting' - L'argument requis 'upload-path' est manquant pour l'hôte dropbox." +warning.config.host.lobfile.missing_api_key: "Problème trouvé dans config.yml à 'resource-pack.delivery.hosting' - L'argument requis 'api-key' est manquant pour l'hôte lobfile." +warning.config.host.onedrive.missing_client_id: "Problème trouvé dans config.yml à 'resource-pack.delivery.hosting' - L'argument requis 'client-id' ou la variable d'environnement 'CE_ONEDRIVE_CLIENT_ID' est manquant pour l'hôte onedrive." +warning.config.host.onedrive.missing_client_secret: "Problème trouvé dans config.yml à 'resource-pack.delivery.hosting' - L'argument requis 'client-secret' ou la variable d'environnement 'CE_ONEDRIVE_CLIENT_SECRET' est manquant pour l'hôte onedrive." +warning.config.host.onedrive.missing_refresh_token: "Problème trouvé dans config.yml à 'resource-pack.delivery.hosting' - L'argument requis 'refresh-token' ou la variable d'environnement 'CE_ONEDRIVE_REFRESH_TOKEN' est manquant pour l'hôte onedrive." +warning.config.host.onedrive.missing_upload_path: "Problème trouvé dans config.yml à 'resource-pack.delivery.hosting' - L'argument requis 'upload-path' est manquant pour l'hôte onedrive." +warning.config.host.s3.missing_endpoint: "Problème trouvé dans config.yml à 'resource-pack.delivery.hosting' - L'argument requis 'endpoint' est manquant pour l'hôte s3." +warning.config.host.s3.missing_protocol: "Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Argument requis 'protocol' manquant pour le host s3." +warning.config.host.s3.missing_bucket: "Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Argument requis 'bucket' manquant pour le host s3." +warning.config.host.s3.missing_region: "Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Argument requis 'region' manquant pour le host s3." +warning.config.host.s3.missing_access_key: "Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Argument requis 'access-key-id' ou variable d'environnement 'CE_S3_ACCESS_KEY_ID' manquant pour le host s3." +warning.config.host.s3.missing_secret: "Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Argument requis 'access-key-secret' ou variable d'environnement 'CE_S3_ACCESS_KEY_SECRET' manquant pour le host s3." +warning.config.host.s3.missing_upload_path: "Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Argument requis 'upload-path' manquant pour le host s3." +warning.config.host.s3.missing_cdn_domain: "Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Argument requis 'cdn.domain' manquant pour le host s3." +warning.config.host.s3.missing_cdn_protocol: "Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Argument requis 'cdn.protocol' manquant pour le host s3." +warning.config.host.self.missing_ip: "Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Argument requis 'ip' manquant pour le host local." +warning.config.host.self.invalid_port: "Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Port invalide '' pour le host local." +warning.config.host.self.invalid_url: "Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - URL invalide '' pour le host local." +warning.config.host.gitlab.missing_url: "Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Argument requis 'gitlab-url' manquant pour le host gitlab." +warning.config.host.gitlab.missing_token: "Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Argument requis 'access-token' manquant pour le host gitlab." +warning.config.host.gitlab.missing_project: "Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Argument requis 'project-id' manquant pour le host gitlab." +warning.config.host.proxy.missing_host: "Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Argument requis 'host' manquant pour le proxy." +warning.config.host.proxy.missing_port: "Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Argument requis 'port' manquant pour le proxy." +warning.config.host.proxy.missing_scheme: "Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Argument requis 'scheme' manquant pour le proxy." +warning.config.host.proxy.invalid: "Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Proxy invalide ''." +warning.config.conflict_matcher.missing_type: "Problème trouvé dans config.yml en section 'resource-pack.duplicated-files-handler' - Argument requis 'type' manquant pour un des gestionnaires." +warning.config.conflict_matcher.invalid_type: "Problème trouvé dans config.yml en section 'resource-pack.duplicated-files-handler' - Un des termes utilise un type invalide ''." +warning.config.conflict_matcher.exact.missing_path: "Problème trouvé dans config.yml en section 'resource-pack.duplicated-files-handler' - Argument requis 'path' manquant pour le comparateur 'exact'." +warning.config.conflict_matcher.contains.missing_path: "Problème trouvé dans config.yml en section 'resource-pack.duplicated-files-handler' - Argument requis 'path' manquant pour le comparateur 'contains'." +warning.config.conflict_matcher.filename.missing_name: "Problème trouvé dans config.yml en section 'resource-pack.duplicated-files-handler' - Argument requis 'path' manquant pour le comparateur 'filename'." +warning.config.conflict_matcher.pattern.missing_pattern: "Problème trouvé dans config.yml en section 'resource-pack.duplicated-files-handler' - Argument requis 'pattern' manquant pour le comparateur 'pattern'." +warning.config.conflict_matcher.parent_prefix.missing_prefix: "Problème trouvé dans config.yml en section 'resource-pack.duplicated-files-handler' - Argument requis 'prefix' manquant pour le comparateur 'parent_path_prefix'." +warning.config.conflict_matcher.parent_suffix.missing_suffix: "Problème trouvé dans config.yml en section 'resource-pack.duplicated-files-handler' - Argument requis 'suffix' manquant pour le comparateur 'parent_path_suffix'." +warning.config.conflict_matcher.inverted.missing_term: "Problème trouvé dans config.yml en section 'resource-pack.duplicated-files-handler' - Argument requis 'term' manquant pour le comparateur 'inverted'." +warning.config.conflict_matcher.all_of.missing_terms: "Problème trouvé dans config.yml en section 'resource-pack.duplicated-files-handler' - Argument requis 'terms' manquant pour le comparateur 'all_of'." +warning.config.conflict_matcher.any_of.missing_terms: "Problème trouvé dans config.yml en section 'resource-pack.duplicated-files-handler' - Argument requis 'terms' manquant pour le comparateur 'any_of'." +warning.config.conflict_resolution.missing_type: "Problème trouvé dans config.yml en section 'resource-pack.duplicated-files-handler' - Argument requis 'type' manquant pour une des résolutions." +warning.config.conflict_resolution.invalid_type: "Problème trouvé dans config.yml en section 'resource-pack.duplicated-files-handler' - Une des résolutions utilise un type invalide ''." +warning.config.event.missing_trigger: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'on' pour les déclencheurs d'événement." +warning.config.event.invalid_trigger: "Problème trouvé dans le fichier - La configuration '' utilise un déclencheur d'événement invalide ''." +warning.config.event.condition.missing_type: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'type' pour la condition d'événement." +warning.config.event.condition.invalid_type: "Problème trouvé dans le fichier - La configuration '' utilise un argument 'type' invalide '' pour la condition d'événement." +warning.config.function.missing_type: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'type' pour la fonction." +warning.config.function.invalid_type: "Problème trouvé dans le fichier - La configuration '' utilise un type de fonction invalide ''." +warning.config.function.command.missing_command: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'command' pour la fonction 'command'." +warning.config.function.actionbar.missing_actionbar: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'actionbar' pour la fonction 'actionbar'." +warning.config.function.message.missing_message: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'message' pour la fonction 'message'." +warning.config.function.open_window.missing_gui_type: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'gui-type' pour la fonction 'open_window'." +warning.config.function.open_window.invalid_gui_type: "Problème trouvé dans le fichier - La configuration '' utilise un type de gui invalide '' pour la fonction 'open_window'. Types autorisés : []." +warning.config.function.run.missing_functions: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'functions' pour la fonction 'run'." +warning.config.function.place_block.missing_block_state: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'block-state' pour la fonction 'place_block'." +warning.config.function.set_food.missing_food: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'food' pour la fonction 'set_food'." +warning.config.function.set_saturation.missing_saturation: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'saturation' pour la fonction 'set_saturation'." +warning.config.function.play_sound.missing_sound: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'sound' pour la fonction 'play_sound'." +warning.config.function.particle.missing_particle: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'particle' pour la fonction 'particle'." +warning.config.function.particle.missing_color: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'color' pour la fonction 'particle'." +warning.config.function.particle.missing_from: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'from' pour la fonction 'particle'." +warning.config.function.particle.missing_to: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'to' pour la fonction 'particle'." +warning.config.function.particle.missing_item: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'item' pour la fonction 'particle'." +warning.config.function.particle.missing_block_state: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'block-state' pour la fonction 'particle'." +warning.config.function.leveler_exp.missing_count: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'count' pour la fonction 'leveler_exp'." +warning.config.function.leveler_exp.missing_leveler: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'leveler' pour la fonction 'leveler_exp'." +warning.config.function.leveler_exp.missing_plugin: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'plugin' pour la fonction 'leveler_exp'." +warning.config.function.remove_potion_effect.missing_potion_effect: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'potion-effect' pour la fonction 'remove_potion_effect'." +warning.config.function.potion_effect.missing_potion_effect: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'potion-effect' pour la fonction 'potion_effect'." +warning.config.function.set_cooldown.missing_time: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'time' pour la fonction 'set_cooldown'." +warning.config.function.set_cooldown.missing_id: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'id' pour la fonction 'set_cooldown'." +warning.config.function.remove_cooldown.missing_id: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'id' pour la fonction 'remove_cooldown'." +warning.config.function.mythic_mobs_skill.missing_skill: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'skill' pour la fonction 'mythic_mobs_skill'." +warning.config.function.spawn_furniture.missing_furniture_id: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'furniture-id' pour la fonction 'spawn_furniture'." +warning.config.function.replace_furniture.missing_furniture_id: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'furniture-id' pour la fonction 'replace_furniture'." +warning.config.function.teleport.missing_x: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'x' pour la fonction 'teleport'." +warning.config.function.teleport.missing_y: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'y' pour la fonction 'teleport'." +warning.config.function.teleport.missing_z: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'z' pour la fonction 'teleport'." +warning.config.function.set_variable.missing_name: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'name' pour la fonction 'set_variable'." +warning.config.function.set_variable.missing_value: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'number' ou 'text' pour la fonction 'set_variable'." +warning.config.function.toast.missing_toast: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'toast' pour la fonction 'toast'." +warning.config.function.toast.missing_icon: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'icon' pour la fonction 'toast'." +warning.config.function.toast.invalid_advancement_type: "Problème trouvé dans le fichier - La configuration '' utilise un type d'avancement invalide '' pour la fonction 'toast'. Types autorisés : []." +warning.config.function.merchant_trade.missing_offers: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'offers' pour la fonction 'merchant_trade'." +warning.config.function.merchant_trade.offer.missing_cost_1: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'cost-1' pour les offres du marchand." +warning.config.function.merchant_trade.offer.missing_result: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'result' pour les offres du marchand." +warning.config.function.when.missing_source: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'source' pour la fonction 'when'." +warning.config.function.if_else.missing_rules: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'rules' pour la fonction 'if_else'." +warning.config.function.update_block_property.missing_properties: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'properties' pour la fonction 'update_block_property'." +warning.config.function.transform_block.missing_block: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'block' pour la fonction 'transform_block'." +warning.config.selector.missing_type: "Problème trouvé dans le fichier - La configuration '' manque l'argument requis 'type' pour le sélecteur." +warning.config.selector.invalid_type: "Problème trouvé dans le fichier - La configuration '' utilise un type de sélecteur invalide ''." +warning.config.selector.invalid_target: "Problème trouvé dans le fichier - La configuration '' utilise une cible de sélecteur invalide ''." +warning.config.resource_pack.item_model.already_exist: "Échec de génération du modèle d'objet pour '' car le fichier '' existe déjà." +warning.config.resource_pack.model.generation.already_exist: "Échec de génération du modèle car le fichier modèle '' existe déjà." +warning.config.resource_pack.generation.malformatted_json: "Le fichier Json '' est mal formaté." +warning.config.resource_pack.generation.missing_font_texture: "La police '' manque la texture requise : ''." +warning.config.resource_pack.generation.missing_model_texture: "Le modèle '' manque la texture ''." +warning.config.resource_pack.generation.missing_item_model: "L'objet '' manque le fichier modèle : ''." +warning.config.resource_pack.generation.missing_block_model: "L'état du bloc '' manque le fichier modèle : ''." +warning.config.resource_pack.generation.missing_parent_model: "Le modèle '' ne trouve pas le modèle parent : ''." +warning.config.resource_pack.generation.missing_equipment_texture: "L'équipement '' manque la texture ''." +warning.config.resource_pack.generation.missing_sound: "L'événement sonore '' manque le fichier ogg ''." +warning.config.resource_pack.generation.texture_not_in_atlas: "La texture '' n'est pas listée dans l'atlas. Vous devez ajouter le chemin de la texture dans l'atlas ou activer l'option 'fix-atlas' dans config.yml." +warning.config.resource_pack.invalid_overlay_format: "Problème trouvé dans config.yml en section 'resource-pack.overlay-format' - Format de superposition invalide ''. Le format doit contenir le placeholder '{version}'." +warning.config.equipment.duplicate: "Problème trouvé dans le fichier - Équipement dupliqué ''. Vérifiez s'il existe la même configuration dans d'autres fichiers." +warning.config.equipment.missing_type: "Problème trouvé dans le fichier - L'équipement '' manque l'argument requis 'type'." +warning.config.equipment.invalid_type: "Problème trouvé dans le fichier - L'équipement '' utilise un argument 'type' invalide." +warning.config.equipment.invalid_sacrificed_armor: "Problème trouvé dans config.yml en section 'equipment.sacrificed-vanilla-armor' - Type d'armure vanilla invalide ''." +warning.config.image.file_not_found: "Problème trouvé dans le fichier - Fichier PNG '' introuvable pour l'image ''." +warning.config.item.model.special.head.missing_texture: "Problème trouvé dans le fichier - L'objet '' manque l'argument requis 'texture' pour le modèle spécial 'minecraft:head'." +warning.config.loot_table.condition.table_bonus.missing_enchantment: "Problème trouvé dans le fichier - '' a une table de butin mal configurée, la condition 'table_bonus' manque l'argument requis 'enchantment'." +warning.config.loot_table.condition.table_bonus.missing_chances: "Problème trouvé dans le fichier - '' a une table de butin mal configurée, la condition 'table_bonus' manque l'argument requis 'chances'." +warning.config.loot_table.number.missing_type: "Problème trouvé dans le fichier - '' a une table de butin mal configurée, un des nombres manque l'argument requis 'type'." +warning.config.loot_table.number.invalid_type: "Problème trouvé dans le fichier - '' a une table de butin mal configurée, un des nombres utilise un type invalide ''." \ No newline at end of file diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index b2a6c3685..52a01b05e 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -220,6 +220,8 @@ warning.config.item.legacy_model.missing_path: "在文件 发现 warning.config.item.legacy_model.overrides.missing_path: "在文件 发现问题 - 物品 '' 的旧版模型覆写规则(overrides)缺少必需的 'path' 参数" warning.config.item.legacy_model.overrides.missing_predicate: "在文件 发现问题 - 物品 '' 的旧版模型覆写规则(overrides)缺少必需的 'predicate' 参数" warning.config.item.legacy_model.cannot_convert: "在文件 发现问题 - 无法将物品 '' 自动转换为旧版格式, 请手动为此物品创建 'legacy-model' 配置项" +warning.config.item.simplified_model.invalid_model: "在文件 中发现配置问题 - 物品 '' 包含的参数数量不匹配. 预期模型数量为 '', 但实际数量为 ''" +warning.config.item.simplified_model.invalid_texture: "在文件 中发现配置问题 - 物品 '' 包含的参数数量不匹配. 预期纹理数量为 '', 但实际数量为 ''" warning.config.item.model.invalid_type: "在文件 发现问题 - 物品 '' 使用了无效的模型类型 ''" warning.config.item.model.tint.missing_type: "在文件 发现问题 - 物品 '' 的染色配置缺少必需的 'type' 参数" warning.config.item.model.tint.invalid_type: "在文件 发现问题 - 物品 '' 使用了无效的染色类型 ''" @@ -353,6 +355,8 @@ warning.config.block.behavior.attached_stem.missing_facing: "在文件 < warning.config.block.behavior.attached_stem.missing_fruit: "在文件 发现问题 - 方块 '' 的 'attached_stem_block' 行为缺少必需的 'fruit' 选项" warning.config.block.behavior.attached_stem.missing_stem: "在文件 发现问题 - 方块 '' 的 'attached_stem_block' 行为缺少必需的 'stem' 选项" warning.config.block.behavior.chime.missing_sounds_projectile_hit: "在文件 发现问题 - 方块 '' 的 'chime_block' 行为缺少必需的 'sounds.projectile-hit' 选项" +warning.config.block.behavior.surface_spreading.missing_base_block: "在文件 发现问题 - 方块 '' 的 'surface_spreading_block' 行为缺少必需的 'base-block' 选项" +warning.config.block.behavior.snowy.missing_snowy: "在文件 发现问题 - 方块 '' 的 'snowy_block' 行为缺少必需的 'snowy' 属性" warning.config.model.generation.missing_parent: "在文件 发现问题 - 配置项 '' 的 'generation' 段落缺少必需的 'parent' 参数" warning.config.model.generation.conflict: "在文件 发现问题 - 无法为 '' 生成模型 存在多个配置尝试使用相同路径 '' 生成不同的 JSON 模型" warning.config.model.generation.invalid_display_position: "在文件 发现问题 - 配置项 '' 在 'generation.display' 区域使用了无效的 display 位置类型 ''. 可用展示类型: []" @@ -476,6 +480,7 @@ warning.config.function.when.missing_source: "在文件 发现 warning.config.function.if_else.missing_rules: "在文件 发现问题 - 配置项 '' 缺少 'if_else' 函数所需的 'rules' 参数" warning.config.function.update_block_property.missing_properties: "在文件 发现问题 - 配置项 '' 缺少 'update_block_property' 函数所需的 'properties' 参数" warning.config.function.transform_block.missing_block: "在文件 发现问题 - 配置项 '' 缺少 'transform_block' 函数所需的 'block' 参数" +warning.config.function.cycle_block_property.missing_property: "在文件 发现问题 - 配置项 '' 缺少 'cycle_block_property' 函数所需的 'property' 参数" warning.config.selector.missing_type: "在文件 发现问题 - 配置项 '' 缺少选择器必需的 'type' 参数" warning.config.selector.invalid_type: "在文件 发现问题 - 配置项 '' 使用了无效的选择器类型 ''" warning.config.selector.invalid_target: "在文件 发现问题 - 配置项 '' 使用了无效的选择器目标 ''" diff --git a/core/src/main/java/net/momirealms/craftengine/core/advancement/AbstractAdvancementManager.java b/core/src/main/java/net/momirealms/craftengine/core/advancement/AbstractAdvancementManager.java index 43711d2f9..8af17d774 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/advancement/AbstractAdvancementManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/advancement/AbstractAdvancementManager.java @@ -8,6 +8,4 @@ public abstract class AbstractAdvancementManager implements AdvancementManager { public AbstractAdvancementManager(CraftEngine plugin) { this.plugin = plugin; } - - } 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 59941bb1f..e9ff489b8 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 @@ -752,7 +752,10 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem json.addProperty("x", ResourceConfigUtils.getAsInt(section.get("x"), "x")); if (section.containsKey("y")) json.addProperty("y", ResourceConfigUtils.getAsInt(section.get("y"), "y")); - if (section.containsKey("uvlock")) json.addProperty("uvlock", ResourceConfigUtils.getAsBoolean(section.get("uvlock"), "uvlock")); + if (section.containsKey("z")) + json.addProperty("z", ResourceConfigUtils.getAsInt(section.get("z"), "z")); + if (section.containsKey("uvlock")) + json.addProperty("uvlock", ResourceConfigUtils.getAsBoolean(section.get("uvlock"), "uvlock")); if (section.containsKey("weight")) json.addProperty("weight", ResourceConfigUtils.getAsInt(section.get("weight"), "weight")); Map generationMap = MiscUtils.castToMap(section.get("generation"), true); 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 60a360a1c..36d7a21db 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 @@ -138,6 +138,5 @@ public abstract class AbstractCustomBlock implements CustomBlock { @Override public void setPlacedBy(BlockPlaceContext context, ImmutableBlockState state) { - this.behavior.setPlacedBy(context, state); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AutoStateGroup.java b/core/src/main/java/net/momirealms/craftengine/core/block/AutoStateGroup.java index 333d43669..569fc7d87 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AutoStateGroup.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AutoStateGroup.java @@ -47,6 +47,11 @@ public enum AutoStateGroup { TRIPWIRE("tripwire", Set.of(BlockKeys.TRIPWIRE), (w) -> true), SUGAR_CANE("sugar_cane", Set.of(BlockKeys.SUGAR_CANE), (w) -> true), CACTUS("cactus", Set.of(BlockKeys.CACTUS), (w) -> true), + CAVE_VINES(List.of("cave_vines", "cave_vine"), Set.of(BlockKeys.CAVE_VINES), (w) -> true), + WEEPING_VINES(List.of("weeping_vines", "weeping_vine"), Set.of(BlockKeys.WEEPING_VINES), (w) -> true), + TWISTING_VINES(List.of("twisting_vines", "twisting_vine"), Set.of(BlockKeys.TWISTING_VINES), (w) -> true), + KELP("kelp", Set.of(BlockKeys.KELP), (w) -> true), + PRESSURE_PLATE("pressure_plate", Set.of(BlockKeys.LIGHT_WEIGHTED_PRESSURE_PLATE, BlockKeys.HEAVY_WEIGHTED_PRESSURE_PLATE), (w) -> true), SAPLING("sapling", Set.of(BlockKeys.OAK_SAPLING, BlockKeys.SPRUCE_SAPLING, BlockKeys.BIRCH_SAPLING, BlockKeys.JUNGLE_SAPLING, BlockKeys.ACACIA_SAPLING, BlockKeys.DARK_OAK_SAPLING, BlockKeys.CHERRY_SAPLING, BlockKeys.PALE_OAK_SAPLING), (w) -> true), MUSHROOM("mushroom", Set.of(BlockKeys.BROWN_MUSHROOM_BLOCK, BlockKeys.RED_MUSHROOM_BLOCK, BlockKeys.MUSHROOM_STEM), (w) -> true), SOLID("solid", Set.of(BlockKeys.BROWN_MUSHROOM_BLOCK, BlockKeys.RED_MUSHROOM_BLOCK, BlockKeys.MUSHROOM_STEM, BlockKeys.NOTE_BLOCK), (w) -> true); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockBehavior.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockBehavior.java index d1aec1f89..310131a79 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockBehavior.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockBehavior.java @@ -10,6 +10,8 @@ import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.world.BlockAccessor; +import net.momirealms.craftengine.core.world.BlockPos; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; @@ -187,6 +189,18 @@ public abstract class BlockBehavior { public void onProjectileHit(Object thisBlock, Object[] args, Callable superMethod) throws Exception { } + // Level/WorldGenLevel level, BlockPos pos, BlockState state, LivingEntity placer, ItemStack itemStack + public void placeMultiState(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + } + + public boolean canPlaceMultiState(BlockAccessor accessor, BlockPos pos, ImmutableBlockState state) { + return true; + } + + public boolean hasMultiState(ImmutableBlockState baseState) { + return false; + } + public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) { return state; } @@ -208,9 +222,6 @@ public abstract class BlockBehavior { return state.settings().replaceable(); } - public void setPlacedBy(BlockPlaceContext context, ImmutableBlockState state) { - } - public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) { return InteractionResult.TRY_EMPTY_HAND; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockKeys.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockKeys.java index f6c63e383..6679672ae 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockKeys.java @@ -45,6 +45,10 @@ public final class BlockKeys { public static final Key CHISELED_BOOKSHELF = Key.of("minecraft:chiseled_bookshelf"); public static final Key LECTERN = Key.of("minecraft:lectern"); public static final Key FARMLAND = Key.of("minecraft:farmland"); + public static final Key CAVE_VINES = Key.of("minecraft:cave_vines"); + public static final Key WEEPING_VINES = Key.of("minecraft:weeping_vines"); + public static final Key TWISTING_VINES = Key.of("minecraft:twisting_vines"); + public static final Key KELP = Key.of("minecraft:kelp"); public static final Key CHEST = Key.of("minecraft:chest"); public static final Key BARREL = Key.of("minecraft:barrel"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateWrapper.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateWrapper.java index 4b86c95c3..407e39003 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateWrapper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateWrapper.java @@ -23,10 +23,14 @@ public interface BlockStateWrapper extends Comparable { BlockStateWrapper withProperty(String propertyName, String propertyValue); + BlockStateWrapper cycleProperty(String propertyName, boolean backwards); + String getAsString(); boolean isCustom(); + boolean isAir(); + @Override default int compareTo(@NotNull BlockStateWrapper o) { return Integer.compare(registryId(), o.registryId()); 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 c46a69faf..2c837d796 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 @@ -14,6 +14,7 @@ import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.registry.Holder; +import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.world.CEWorld; import net.momirealms.craftengine.core.world.World; import net.momirealms.sparrow.nbt.CompoundTag; @@ -152,6 +153,16 @@ public final class ImmutableBlockState { return this.owner; } + public > ImmutableBlockState cycle(Property property, boolean backwards) { + T currentValue = get(property); + List values = property.possibleValues(); + return with(property, getRelative(values, currentValue, backwards)); + } + + private static T getRelative(List values, T currentValue, boolean backwards) { + return backwards ? MiscUtils.findPreviousInIterable(values, currentValue) : getNextValue(values, currentValue); + } + public > ImmutableBlockState cycle(Property property) { T currentValue = get(property); List values = property.possibleValues(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/StatePropertyAccessor.java b/core/src/main/java/net/momirealms/craftengine/core/block/StatePropertyAccessor.java index 1277e0b1e..f25d3e14d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/StatePropertyAccessor.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/StatePropertyAccessor.java @@ -16,4 +16,12 @@ public interface StatePropertyAccessor { @NotNull Object withProperty(String propertyName, String value); + + @NotNull + default Object cycleProperty(String propertyName) { + return cycleProperty(propertyName, false); + } + + @NotNull + Object cycleProperty(String propertyName, boolean backwards); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/behavior/special/FallOnBlockBehavior.java b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/FallOnBlockBehavior.java similarity index 90% rename from core/src/main/java/net/momirealms/craftengine/core/block/behavior/special/FallOnBlockBehavior.java rename to core/src/main/java/net/momirealms/craftengine/core/block/behavior/FallOnBlockBehavior.java index 5376477a7..344f63214 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/behavior/special/FallOnBlockBehavior.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/FallOnBlockBehavior.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.core.block.behavior.special; +package net.momirealms.craftengine.core.block.behavior; import java.util.concurrent.Callable; diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/behavior/special/PlaceLiquidBlockBehavior.java b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/PlaceLiquidBlockBehavior.java similarity index 80% rename from core/src/main/java/net/momirealms/craftengine/core/block/behavior/special/PlaceLiquidBlockBehavior.java rename to core/src/main/java/net/momirealms/craftengine/core/block/behavior/PlaceLiquidBlockBehavior.java index ddab31b4f..785c7f994 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/behavior/special/PlaceLiquidBlockBehavior.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/PlaceLiquidBlockBehavior.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.core.block.behavior.special; +package net.momirealms.craftengine.core.block.behavior; import java.util.concurrent.Callable; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java index 94f5fcee3..7be7636f8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItem.java @@ -320,6 +320,16 @@ public class AbstractItem, I> implements Item { return this.factory.getEnchantment(this.item, enchantmentId); } + @Override + public Optional> enchantments() { + return this.factory.enchantments(this.item); + } + + @Override + public Optional> storedEnchantments() { + return this.factory.storedEnchantments(this.item); + } + @Override public Item setEnchantments(List enchantments) { this.factory.enchantments(this.item, enchantments); 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 92d8269f8..d6defc9b4 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 @@ -20,6 +20,7 @@ import net.momirealms.craftengine.core.pack.model.generation.AbstractModelGenera import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.pack.model.select.ChargeTypeSelectProperty; import net.momirealms.craftengine.core.pack.model.select.TrimMaterialSelectProperty; +import net.momirealms.craftengine.core.pack.model.simplified.SimplifiedModelReader; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigParser; @@ -231,6 +232,13 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl return Collections.unmodifiableList(this.customItemTags.getOrDefault(tag, List.of())); } + @Override + public Collection itemTags() { + Set tags = new HashSet<>(VANILLA_ITEM_TAGS.keySet()); + tags.addAll(this.customItemTags.keySet()); + return tags; + } + @Override public Collection cachedCustomItemSuggestions() { return Collections.unmodifiableCollection(this.cachedCustomItemSuggestions); @@ -477,7 +485,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl if (throwable != null) { // 检测custom model data 冲突 if (throwable instanceof IdAllocator.IdConflictException exception) { - if (section.containsKey("model") || section.containsKey("legacy-model")) { + if (section.containsKey("model") || section.containsKey("models") || section.containsKey("texture") || section.containsKey("textures") || section.containsKey("legacy-model")) { throw new LocalizedResourceConfigException("warning.config.item.custom_model_data.conflict", String.valueOf(exception.id()), exception.previousOwner()); } customModelData = exception.id(); @@ -518,24 +526,69 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl CustomItem.Builder itemBuilder = createPlatformItemBuilder(uniqueId, material, clientBoundMaterial); - // 模型配置区域,如果这里被配置了,那么用户必须要配置custom-model-data或item-model - // model可以是一个string也可以是一个区域 - Object modelSection = section.get("model"); - Map legacyModelSection = MiscUtils.castToMap(section.get("legacy-model"), true); - boolean hasModelSection = modelSection != null || legacyModelSection != null; - - if (customModelData > 0 && (hasModelSection || forceCustomModelData)) { - if (clientBoundModel) itemBuilder.clientBoundDataModifier(new CustomModelDataModifier<>(customModelData)); - else itemBuilder.dataModifier(new CustomModelDataModifier<>(customModelData)); - } - if (itemModel != null && (hasModelSection || forceItemModel)) { - if (clientBoundModel) itemBuilder.clientBoundDataModifier(new ItemModelModifier<>(itemModel)); - else itemBuilder.dataModifier(new ItemModelModifier<>(itemModel)); - } // 对于不重要的配置,可以仅警告,不返回 ExceptionCollector collector = new ExceptionCollector<>(); + // 模型配置区域,如果这里被配置了,那么用户可以配置custom-model-data或item-model + // model可以是一个string也可以是一个区域 + Object modelSection = ResourceConfigUtils.get(section, "model", "models"); + Map legacyModelSection = MiscUtils.castToMap(section.get("legacy-model"), true); + // model可以是一个map,也可以是一个string或list + boolean hasModelSection = modelSection instanceof Map || legacyModelSection != null; + if (!hasModelSection) { + Object texture = ResourceConfigUtils.get(section, "texture", "textures"); + // 如果使用的是textures,那么model指的是 + if (texture != null) { + // 获取textures列表 + List textures = texture instanceof List ? MiscUtils.getAsStringList(texture) : List.of(texture.toString()); + if (!textures.isEmpty()) { + // 获取可选的模型列表,此时的model不可能是map了 + List modelPath = modelSection != null ? MiscUtils.getAsStringList(modelSection) : List.of(); + // 根据父item model选择处理方案 + Key templateModel = itemModel != null && AbstractPackManager.PRESET_MODERN_MODELS_ITEM.containsKey(itemModel) ? itemModel : clientBoundMaterial; + SimplifiedModelReader simplifiedModelReader = AbstractPackManager.SIMPLIFIED_MODEL_READERS.get(templateModel); + if (simplifiedModelReader != null) { + try { + modelSection = simplifiedModelReader.convert(textures, modelPath, id); + if (modelSection != null) { + hasModelSection = true; + } + } catch (LocalizedResourceConfigException e) { + collector.add(e); + } + } + } + } + // 如果没有配贴图,且model为string或list,直接生成相应类型的模型 + else if (modelSection != null) { + List models = modelSection instanceof List ? MiscUtils.getAsStringList(modelSection) : List.of(modelSection.toString()); + if (!models.isEmpty()) { + Key templateModel = itemModel != null && AbstractPackManager.PRESET_MODERN_MODELS_ITEM.containsKey(itemModel) ? itemModel : clientBoundMaterial; + SimplifiedModelReader simplifiedModelReader = AbstractPackManager.SIMPLIFIED_MODEL_READERS.get(templateModel); + if (simplifiedModelReader != null) { + try { + modelSection = simplifiedModelReader.convert(models); + if (modelSection != null) { + hasModelSection = true; + } + } catch (LocalizedResourceConfigException e) { + collector.add(e); + } + } + } + } + } + + if (customModelData > 0 && (hasModelSection || forceCustomModelData)) { + if (clientBoundModel) itemBuilder.clientBoundDataModifier(new OverwritableCustomModelDataModifier<>(customModelData)); + else itemBuilder.dataModifier(new CustomModelDataModifier<>(customModelData)); + } + if (itemModel != null && (hasModelSection || forceItemModel)) { + if (clientBoundModel) itemBuilder.clientBoundDataModifier(new OverwritableItemModelModifier<>(itemModel)); + else itemBuilder.dataModifier(new ItemModelModifier<>(itemModel)); + } + // 应用物品数据 try { applyDataModifiers(MiscUtils.castToMap(section.get("data"), true), itemBuilder::dataModifier); @@ -559,7 +612,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl // 事件 Map>> eventTriggerListMap; try { - eventTriggerListMap = EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event")); + eventTriggerListMap = EventFunctions.parseEvents(ResourceConfigUtils.get(section, "event", "events")); } catch (LocalizedResourceConfigException e) { collector.add(e); eventTriggerListMap = Map.of(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/Item.java b/core/src/main/java/net/momirealms/craftengine/core/item/Item.java index d1e32bc46..5b7c2f563 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/Item.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/Item.java @@ -150,6 +150,10 @@ public interface Item { Optional getEnchantment(Key enchantmentId); + Optional> enchantments(); + + Optional> storedEnchantments(); + Item setEnchantments(List enchantments); Item setStoredEnchantments(List enchantments); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java index 5125d57c6..04be0624b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemFactory.java @@ -148,6 +148,10 @@ public abstract class ItemFactory, I> { protected abstract void maxDamage(W item, Integer damage); + protected abstract Optional> enchantments(W item); + + protected abstract Optional> storedEnchantments(W item); + protected abstract void enchantments(W item, List enchantments); protected abstract void storedEnchantments(W item, List enchantments); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java index f408f7e4c..3b017a27a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemManager.java @@ -101,6 +101,8 @@ public interface ItemManager extends Manageable, ModelGenerator { int fuelTime(Key id); + Collection itemTags(); + Collection cachedCustomItemSuggestions(); Collection cachedAllItemSuggestions(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/context/BlockPlaceContext.java b/core/src/main/java/net/momirealms/craftengine/core/item/context/BlockPlaceContext.java index 2cb96abb7..e994f419e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/context/BlockPlaceContext.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/context/BlockPlaceContext.java @@ -21,7 +21,7 @@ public class BlockPlaceContext extends UseOnContext { super(world, player, hand, stack, hit); this.relativePos = hit.getBlockPos().relative(hit.getDirection()); this.replaceClicked = true; - this.replaceClicked = world.getBlockAt(hit.getBlockPos()).canBeReplaced(this); + this.replaceClicked = world.getBlock(hit.getBlockPos()).canBeReplaced(this); } @Override @@ -34,11 +34,11 @@ public class BlockPlaceContext extends UseOnContext { } public boolean canPlace() { - return this.replaceClicked || this.getLevel().getBlockAt(this.getClickedPos()).canBeReplaced(this); + return this.replaceClicked || this.getLevel().getBlock(this.getClickedPos()).canBeReplaced(this); } public boolean isWaterSource() { - return this.getLevel().getBlockAt(this.getClickedPos()).isWaterSource(this); + return this.getLevel().getBlock(this.getClickedPos()).isWaterSource(this); } public boolean replacingClickedOnBlock() { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EnchantmentsModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EnchantmentsModifier.java index 24c55f3a1..4f8b4b539 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EnchantmentsModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/EnchantmentsModifier.java @@ -9,15 +9,24 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; public class EnchantmentsModifier implements SimpleNetworkItemDataModifier { public static final Factory FACTORY = new Factory<>(); private static final Object[] STORED_ENCHANTMENTS = new Object[] {"StoredEnchantments"}; private static final Object[] ENCHANTMENTS = new Object[] {"Enchantments"}; private final List enchantments; + private final boolean merge; - public EnchantmentsModifier(List enchantments) { + public EnchantmentsModifier(List enchantments, boolean merge) { this.enchantments = enchantments; + this.merge = merge; + } + + public boolean merge() { + return merge; } public List enchantments() { @@ -32,8 +41,38 @@ public class EnchantmentsModifier implements SimpleNetworkItemDataModifier @Override public Item apply(Item item, ItemBuildContext context) { if (item.vanillaId().equals(ItemKeys.ENCHANTED_BOOK)) { + if (this.merge) { + Optional> previousEnchantments = item.storedEnchantments(); + if (previousEnchantments.isPresent()) { + return item.setStoredEnchantments(Stream.concat(previousEnchantments.get().stream(), this.enchantments.stream()) + .collect(Collectors.toMap( + Enchantment::id, + enchantment -> enchantment, + (existing, replacement) -> + existing.level() > replacement.level() ? existing : replacement + )) + .values() + .stream() + .toList()); + } + } return item.setStoredEnchantments(this.enchantments); } else { + if (this.merge) { + Optional> previousEnchantments = item.enchantments(); + if (previousEnchantments.isPresent()) { + return item.setEnchantments(Stream.concat(previousEnchantments.get().stream(), this.enchantments.stream()) + .collect(Collectors.toMap( + Enchantment::id, + enchantment -> enchantment, + (existing, replacement) -> + existing.level() > replacement.level() ? existing : replacement + )) + .values() + .stream() + .toList()); + } + } return item.setEnchantments(this.enchantments); } } @@ -57,14 +96,19 @@ public class EnchantmentsModifier implements SimpleNetworkItemDataModifier @Override public ItemDataModifier create(Object arg) { - Map data = ResourceConfigUtils.getAsMap(arg, "enchantments"); + Map enchantData = ResourceConfigUtils.getAsMap(arg, "enchantments"); List enchantments = new ArrayList<>(); - for (Map.Entry e : data.entrySet()) { + boolean merge = false; + if (enchantData.containsKey("enchantments")) { + merge = ResourceConfigUtils.getAsBoolean(enchantData.get("merge"), "merge"); + enchantData = ResourceConfigUtils.getAsMap(enchantData.get("enchantments"), "enchantments"); + } + for (Map.Entry e : enchantData.entrySet()) { if (e.getValue() instanceof Number number) { enchantments.add(new Enchantment(Key.of(e.getKey()), number.intValue())); } } - return new EnchantmentsModifier<>(enchantments); + return new EnchantmentsModifier<>(enchantments, merge); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifiers.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifiers.java index e35e432fb..b0064ce8e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifiers.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemDataModifiers.java @@ -15,6 +15,7 @@ public final class ItemDataModifiers { private ItemDataModifiers() {} public static final Key ITEM_MODEL = Key.of("craftengine:item-model"); + public static final Key OVERWRITABLE_ITEM_MODEL = Key.of("craftengine:overwritable-item-model"); public static final Key ID = Key.of("craftengine:id"); public static final Key HIDE_TOOLTIP = Key.of("craftengine:hide-tooltip"); public static final Key FOOD = Key.of("craftengine:food"); @@ -27,6 +28,7 @@ public final class ItemDataModifiers { public static final Key DISPLAY_NAME = Key.of("craftengine:display-name"); public static final Key CUSTOM_NAME = Key.of("craftengine:custom-name"); public static final Key CUSTOM_MODEL_DATA = Key.of("craftengine:custom-model-data"); + public static final Key OVERWRITABLE_CUSTOM_MODEL_DATA = Key.of("craftengine:overwritable-custom-model-data"); public static final Key COMPONENTS = Key.of("craftengine:components"); public static final Key COMPONENT = Key.of("craftengine:component"); public static final Key ATTRIBUTE_MODIFIERS = Key.of("craftengine:attribute-modifiers"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/OverwritableCustomModelDataModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/OverwritableCustomModelDataModifier.java new file mode 100644 index 000000000..1d0227a15 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/OverwritableCustomModelDataModifier.java @@ -0,0 +1,58 @@ +package net.momirealms.craftengine.core.item.modifier; + +import net.momirealms.craftengine.core.item.DataComponentKeys; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.ItemDataModifierFactory; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import org.jetbrains.annotations.Nullable; + +public class OverwritableCustomModelDataModifier implements SimpleNetworkItemDataModifier { + public static final Factory FACTORY = new Factory<>(); + private final int argument; + + public OverwritableCustomModelDataModifier(int argument) { + this.argument = argument; + } + + public int customModelData() { + return this.argument; + } + + @Override + public Key type() { + return ItemDataModifiers.OVERWRITABLE_CUSTOM_MODEL_DATA; + } + + @Override + public Item apply(Item item, ItemBuildContext context) { + if (item.customModelData().isPresent()) return item; + item.customModelData(this.argument); + return item; + } + + @Override + public @Nullable Key componentType(Item item, ItemBuildContext context) { + return DataComponentKeys.CUSTOM_MODEL_DATA; + } + + @Override + public @Nullable Object[] nbtPath(Item item, ItemBuildContext context) { + return new Object[]{"CustomModelData"}; + } + + @Override + public String nbtPathString(Item item, ItemBuildContext context) { + return "CustomModelData"; + } + + public static class Factory implements ItemDataModifierFactory { + + @Override + public ItemDataModifier create(Object arg) { + int customModelData = ResourceConfigUtils.getAsInt(arg, "custom-model-data"); + return new OverwritableCustomModelDataModifier<>(customModelData); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/OverwritableItemModelModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/OverwritableItemModelModifier.java new file mode 100644 index 000000000..9e54d05bc --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/OverwritableItemModelModifier.java @@ -0,0 +1,46 @@ +package net.momirealms.craftengine.core.item.modifier; + +import net.momirealms.craftengine.core.item.DataComponentKeys; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.ItemDataModifierFactory; +import net.momirealms.craftengine.core.util.Key; +import org.jetbrains.annotations.Nullable; + +public class OverwritableItemModelModifier implements SimpleNetworkItemDataModifier { + public static final Factory FACTORY = new Factory<>(); + private final Key data; + + public OverwritableItemModelModifier(Key data) { + this.data = data; + } + + public Key data() { + return data; + } + + @Override + public Key type() { + return ItemDataModifiers.OVERWRITABLE_CUSTOM_MODEL_DATA; + } + + @Override + public Item apply(Item item, ItemBuildContext context) { + if (item.hasNonDefaultComponent(DataComponentKeys.ITEM_MODEL)) return item; + return item.itemModel(this.data.asString()); + } + + @Override + public @Nullable Key componentType(Item item, ItemBuildContext context) { + return DataComponentKeys.ITEM_MODEL; + } + + public static class Factory implements ItemDataModifierFactory { + + @Override + public ItemDataModifier create(Object arg) { + String id = arg.toString(); + return new OverwritableItemModelModifier<>(Key.of(id)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java index 1c41c1f38..b98b86b27 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java @@ -143,9 +143,12 @@ public abstract class AbstractRecipeSerializer> implement Set itemIds = new HashSet<>(); Set minecraftItemIds = new HashSet<>(); ItemManager itemManager = CraftEngine.instance().itemManager(); + List elements = new ArrayList<>(); for (String item : items) { if (item.charAt(0) == '#') { - List uniqueKeys = itemManager.itemIdsByTag(Key.of(item.substring(1))); + Key tag = Key.of(item.substring(1)); + elements.add(new IngredientElement.Tag(tag)); + List uniqueKeys = itemManager.itemIdsByTag(tag); itemIds.addAll(uniqueKeys); for (UniqueKey uniqueKey : uniqueKeys) { List ingredientSubstitutes = itemManager.getIngredientSubstitutes(uniqueKey.key()); @@ -155,6 +158,7 @@ public abstract class AbstractRecipeSerializer> implement } } else { Key itemId = Key.of(item); + elements.add(new IngredientElement.Item(itemId)); if (itemManager.getBuildableItem(itemId).isEmpty()) { throw new LocalizedResourceConfigException("warning.config.recipe.invalid_ingredient", item); } @@ -189,6 +193,6 @@ public abstract class AbstractRecipeSerializer> implement } minecraftItemIds.add(vanillaItem); } - return itemIds.isEmpty() ? null : Ingredient.of(itemIds, minecraftItemIds, hasCustomItem); + return itemIds.isEmpty() ? null : Ingredient.of(elements, itemIds, minecraftItemIds, hasCustomItem); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBlastingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBlastingRecipe.java index 4cd515793..a013537a3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBlastingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomBlastingRecipe.java @@ -42,7 +42,7 @@ public class CustomBlastingRecipe extends CustomCookingRecipe { parseResult(arguments), arguments.containsKey("group") ? arguments.get("group").toString() : null, cookingRecipeCategory(arguments), singleInputIngredient(arguments), ResourceConfigUtils.getAsInt(arguments.getOrDefault("time", 80), "time"), - ResourceConfigUtils.getAsFloat(arguments.getOrDefault("experience", 0.0f), "experience") + ResourceConfigUtils.getAsFloat(ResourceConfigUtils.get(arguments, "exp", "experience"), "experience") ); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCampfireRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCampfireRecipe.java index 16fa94a62..4c8545e1a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCampfireRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCampfireRecipe.java @@ -42,7 +42,7 @@ public class CustomCampfireRecipe extends CustomCookingRecipe { parseResult(arguments), arguments.containsKey("group") ? arguments.get("group").toString() : null, cookingRecipeCategory(arguments), singleInputIngredient(arguments), ResourceConfigUtils.getAsInt(arguments.getOrDefault("time", 80), "time"), - ResourceConfigUtils.getAsFloat(arguments.getOrDefault("experience", 0.0f), "experience") + ResourceConfigUtils.getAsFloat(ResourceConfigUtils.get(arguments, "exp", "experience"), "experience") ); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmeltingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmeltingRecipe.java index 9df7351f2..cbb2663c5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmeltingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmeltingRecipe.java @@ -42,7 +42,7 @@ public class CustomSmeltingRecipe extends CustomCookingRecipe { parseResult(arguments), arguments.containsKey("group") ? arguments.get("group").toString() : null, cookingRecipeCategory(arguments), singleInputIngredient(arguments), ResourceConfigUtils.getAsInt(arguments.getOrDefault("time", 80), "time"), - ResourceConfigUtils.getAsFloat(arguments.getOrDefault("experience", 0.0f), "experience") + ResourceConfigUtils.getAsFloat(ResourceConfigUtils.get(arguments, "exp", "experience"), "experience") ); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java index 42aca19c0..190ee8004 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmithingTransformRecipe.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.item.recipe; import com.google.gson.JsonObject; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.data.Enchantment; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; import net.momirealms.craftengine.core.item.recipe.input.SmithingInput; import net.momirealms.craftengine.core.item.recipe.result.CustomRecipeResult; @@ -22,6 +23,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.Stream; public class CustomSmithingTransformRecipe extends AbstractedFixedResultRecipe implements ConditionalRecipe, VisualResultRecipe, FunctionalRecipe { @@ -30,6 +33,7 @@ public class CustomSmithingTransformRecipe extends AbstractedFixedResultRecip private final Ingredient template; private final Ingredient addition; private final boolean mergeComponents; + private final boolean mergeEnchantments; private final List processors; private final Condition condition; private final Function[] smithingFunctions; @@ -44,6 +48,7 @@ public class CustomSmithingTransformRecipe extends AbstractedFixedResultRecip @Nullable CustomRecipeResult visualResult, List processors, boolean mergeComponents, + boolean mergeEnchantments, Function[] smithingFunctions, Condition condition ) { @@ -53,11 +58,20 @@ public class CustomSmithingTransformRecipe extends AbstractedFixedResultRecip this.addition = addition; this.processors = processors; this.mergeComponents = mergeComponents; + this.mergeEnchantments = mergeEnchantments; this.condition = condition; this.smithingFunctions = smithingFunctions; this.visualResult = visualResult; } + public boolean mergeComponents() { + return mergeComponents; + } + + public boolean mergeEnchantments() { + return mergeEnchantments; + } + @Override public Function[] functions() { return this.smithingFunctions; @@ -179,6 +193,7 @@ public class CustomSmithingTransformRecipe extends AbstractedFixedResultRecip List template = MiscUtils.getAsStringList(arguments.get("template-type")); List addition = MiscUtils.getAsStringList(arguments.get("addition")); boolean mergeComponents = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("merge-components", true), "merge-components"); + boolean mergeEnchantments = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("merge-enchantments", false), "merge-enchantments"); @SuppressWarnings("unchecked") List> processors = (List>) arguments.getOrDefault("post-processors", List.of()); return new CustomSmithingTransformRecipe<>(id, @@ -190,6 +205,7 @@ public class CustomSmithingTransformRecipe extends AbstractedFixedResultRecip parseVisualResult(arguments), ItemDataProcessors.fromMapList(processors), mergeComponents, + mergeEnchantments, functions(arguments), conditions(arguments) ); } @@ -206,6 +222,7 @@ public class CustomSmithingTransformRecipe extends AbstractedFixedResultRecip null, null, true, + false, null, null ); } @@ -214,6 +231,7 @@ public class CustomSmithingTransformRecipe extends AbstractedFixedResultRecip public static class ItemDataProcessors { public static final Key KEEP_COMPONENTS = Key.of("craftengine:keep_components"); public static final Key KEEP_TAGS = Key.of("craftengine:keep_tags"); + public static final Key MERGE_ENCHANTMENTS = Key.of("craftengine:merge_enchantments"); static { if (VersionHelper.isOrAbove1_20_5()) { @@ -221,6 +239,7 @@ public class CustomSmithingTransformRecipe extends AbstractedFixedResultRecip } else { register(KEEP_TAGS, KeepTags.FACTORY); } + register(MERGE_ENCHANTMENTS, MergeEnchantments.FACTORY); } public static List fromMapList(List> mapList) { @@ -260,6 +279,42 @@ public class CustomSmithingTransformRecipe extends AbstractedFixedResultRecip } } + public static class MergeEnchantments implements ItemDataProcessor { + public static final MergeEnchantments INSTANCE = new MergeEnchantments(); + public static final Factory FACTORY = new Factory(); + + @Override + public Key type() { + return ItemDataProcessors.MERGE_ENCHANTMENTS; + } + + @Override + public void accept(Item item1, Item item2, Item item3) { + item1.enchantments().ifPresent(e1 -> { + item3.enchantments().ifPresent(e2 -> { + item3.setEnchantments(Stream.concat(e1.stream(), e2.stream()) + .collect(Collectors.toMap( + Enchantment::id, + enchantment -> enchantment, + (existing, replacement) -> + existing.level() > replacement.level() ? existing : replacement + )) + .values() + .stream() + .toList()); + }); + }); + } + + public static class Factory implements ProcessorFactory { + + @Override + public ItemDataProcessor create(Map arguments) { + return INSTANCE; + } + } + } + public static class KeepComponents implements ItemDataProcessor { public static final Factory FACTORY = new Factory(); private final List components; diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmokingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmokingRecipe.java index 357d047f4..8002009b6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmokingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomSmokingRecipe.java @@ -42,7 +42,7 @@ public class CustomSmokingRecipe extends CustomCookingRecipe { parseResult(arguments), arguments.containsKey("group") ? arguments.get("group").toString() : null, cookingRecipeCategory(arguments), singleInputIngredient(arguments), ResourceConfigUtils.getAsInt(arguments.getOrDefault("time", 80), "time"), - ResourceConfigUtils.getAsFloat(arguments.getOrDefault("experience", 0.0f), "experience") + ResourceConfigUtils.getAsFloat(ResourceConfigUtils.get(arguments, "exp", "experience"), "experience") ); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/Ingredient.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/Ingredient.java index 6d2f1ce02..72c0fc3d6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/Ingredient.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/Ingredient.java @@ -6,6 +6,7 @@ import java.util.*; import java.util.function.Predicate; public class Ingredient implements Predicate>, StackedContents.IngredientInfo { + private final List elements; // 自定义物品与原版物品混合的列表 private final List items; // 自定义物品原版材质与原版物品混合的列表 @@ -13,7 +14,8 @@ public class Ingredient implements Predicate>, StackedContent // ingredient里是否含有自定义物品 private final boolean hasCustomItem; - private Ingredient(List items, List vanillaItems, boolean hasCustomItem) { + private Ingredient(List elements, List items, List vanillaItems, boolean hasCustomItem) { + this.elements = List.copyOf(elements); this.items = List.copyOf(items); this.vanillaItems = List.copyOf(vanillaItems); this.hasCustomItem = hasCustomItem; @@ -24,12 +26,8 @@ public class Ingredient implements Predicate>, StackedContent .orElseGet(stack::isEmpty); } - public static Ingredient of(Set items, Set minecraftItems, boolean hasCustomItem) { - return new Ingredient<>(new ArrayList<>(items), new ArrayList<>(minecraftItems), hasCustomItem); - } - - public boolean hasCustomItem() { - return hasCustomItem; + public static Ingredient of(List elements, Set items, Set minecraftItems, boolean hasCustomItem) { + return new Ingredient<>(elements, new ArrayList<>(items), new ArrayList<>(minecraftItems), hasCustomItem); } @Override @@ -42,6 +40,14 @@ public class Ingredient implements Predicate>, StackedContent return false; } + public List elements() { + return this.elements; + } + + public boolean hasCustomItem() { + return this.hasCustomItem; + } + public List items() { return this.items; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/IngredientElement.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/IngredientElement.java new file mode 100644 index 000000000..d84952dd8 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/IngredientElement.java @@ -0,0 +1,20 @@ +package net.momirealms.craftengine.core.item.recipe; + +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.UniqueKey; + +import java.util.List; + +public sealed interface IngredientElement permits IngredientElement.Item, IngredientElement.Tag { + + record Item(Key id) implements IngredientElement { + } + + record Tag(Key tag) implements IngredientElement { + + public List items() { + return CraftEngine.instance().itemManager().itemIdsByTag(this.tag); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/function/ApplyDataFunction.java b/core/src/main/java/net/momirealms/craftengine/core/loot/function/ApplyDataFunction.java index 168d9e6fa..2d870d95f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/function/ApplyDataFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/function/ApplyDataFunction.java @@ -3,12 +3,9 @@ package net.momirealms.craftengine.core.loot.function; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; -import net.momirealms.craftengine.core.item.recipe.result.ApplyItemDataPostProcessor; import net.momirealms.craftengine.core.loot.LootConditions; import net.momirealms.craftengine.core.loot.LootContext; import net.momirealms.craftengine.core.plugin.context.Condition; -import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; -import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index 6981623e8..1246d5bad 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -7,6 +7,7 @@ import com.google.common.jimfs.Jimfs; import com.google.gson.*; import net.momirealms.craftengine.core.font.BitmapImage; import net.momirealms.craftengine.core.font.Font; +import net.momirealms.craftengine.core.item.ItemKeys; import net.momirealms.craftengine.core.item.equipment.ComponentBasedEquipment; import net.momirealms.craftengine.core.item.equipment.Equipment; import net.momirealms.craftengine.core.item.equipment.TrimBasedEquipment; @@ -22,6 +23,7 @@ import net.momirealms.craftengine.core.pack.model.RangeDispatchItemModel; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.pack.model.generation.ModelGenerator; import net.momirealms.craftengine.core.pack.model.rangedisptach.CustomModelDataRangeDispatchProperty; +import net.momirealms.craftengine.core.pack.model.simplified.*; import net.momirealms.craftengine.core.pack.revision.Revision; import net.momirealms.craftengine.core.pack.revision.Revisions; import net.momirealms.craftengine.core.plugin.CraftEngine; @@ -67,16 +69,28 @@ import static net.momirealms.craftengine.core.util.MiscUtils.castToMap; @SuppressWarnings("DuplicatedCode") public abstract class AbstractPackManager implements PackManager { + // 1.21.4+物品模型 public static final Map PRESET_MODERN_MODELS_ITEM = new HashMap<>(); + // 旧版本的物品模型 public static final Map PRESET_LEGACY_MODELS_ITEM = new HashMap<>(); + // 全版本的方块模型 public static final Map PRESET_MODELS_BLOCK = new HashMap<>(); + // 1.21.4+物品模型定义 public static final Map PRESET_ITEMS = new HashMap<>(); + + // 原版资产id public static final Set VANILLA_TEXTURES = new HashSet<>(); public static final Set VANILLA_MODELS = new HashSet<>(); public static final Set VANILLA_SOUNDS = new HashSet<>(); + + // 简化的model读取器 + public static final Map SIMPLIFIED_MODEL_READERS = new HashMap<>(); + public static final String NEW_TRIM_MATERIAL = "custom"; + public static final Set ALLOWED_VANILLA_EQUIPMENT = Set.of("chainmail", "diamond", "gold", "iron", "netherite"); public static final Set ALLOWED_MODEL_TAGS = Set.of("parent", "ambientocclusion", "display", "textures", "elements", "gui_light", "overrides"); + private static final byte[] EMPTY_1X1_IMAGE; private static final byte[] EMPTY_EQUIPMENT_IMAGE; private static final byte[] EMPTY_16X16_IMAGE; @@ -179,6 +193,28 @@ public abstract class AbstractPackManager implements PackManager { } loadInternalList("internal/textures/processed.json", VANILLA_TEXTURES::add); loadInternalList("internal/sounds/processed.json", VANILLA_SOUNDS::add); + + // 不是一个非常好的方案 + for (Key item : PRESET_ITEMS.keySet()) { + JsonObject jsonObject = PRESET_MODERN_MODELS_ITEM.get(item); + if (jsonObject != null) { + JsonElement parent = jsonObject.get("parent"); + if (parent instanceof JsonPrimitive primitive) { + String parentModel = primitive.getAsString(); + if (parentModel.equals("minecraft:item/handheld")) { + SIMPLIFIED_MODEL_READERS.put(item, GeneratedModelReader.HANDHELD); + continue; + } + } + } + SIMPLIFIED_MODEL_READERS.put(item, GeneratedModelReader.GENERATED); + } + + SIMPLIFIED_MODEL_READERS.put(ItemKeys.FISHING_ROD, ConditionModelReader.FISHING_ROD); + SIMPLIFIED_MODEL_READERS.put(ItemKeys.ELYTRA, ConditionModelReader.ELYTRA); + SIMPLIFIED_MODEL_READERS.put(ItemKeys.SHIELD, ConditionModelReader.SHIELD); + SIMPLIFIED_MODEL_READERS.put(ItemKeys.BOW, BowModelReader.INSTANCE); + SIMPLIFIED_MODEL_READERS.put(ItemKeys.CROSSBOW, CrossbowModelReader.INSTANCE); } private void loadModernItemModel(String path, BiConsumer callback) { @@ -265,9 +301,8 @@ public abstract class AbstractPackManager implements PackManager { } @Override - public void loadResources(boolean recipe) { - this.loadPacks(); - this.loadResourceConfigs(recipe ? (p) -> true : (p) -> p.loadingSequence() != LoadingSequence.RECIPE); + public void loadResources(Predicate predicate) { + this.loadResourceConfigs(predicate); } @Override @@ -326,7 +361,8 @@ public abstract class AbstractPackManager implements PackManager { return true; } - private void loadPacks() { + @Override + public void loadPacks() { Path resourcesFolder = this.plugin.dataFolderPath().resolve("resources"); try { if (Files.notExists(resourcesFolder)) { @@ -428,7 +464,12 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/resourcepack/pack.mcmeta"); plugin.saveResource("resources/default/resourcepack/pack.png"); // configs - plugin.saveResource("resources/default/configuration/templates.yml"); + plugin.saveResource("resources/default/configuration/templates/block_settings.yml"); + plugin.saveResource("resources/default/configuration/templates/block_states.yml"); + plugin.saveResource("resources/default/configuration/templates/models.yml"); + plugin.saveResource("resources/default/configuration/templates/loot_tables.yml"); + plugin.saveResource("resources/default/configuration/templates/recipes.yml"); + plugin.saveResource("resources/default/configuration/templates/tool_levels.yml"); plugin.saveResource("resources/default/configuration/categories.yml"); plugin.saveResource("resources/default/configuration/emoji.yml"); plugin.saveResource("resources/default/configuration/translations.yml"); @@ -503,7 +544,7 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_" + item + ".png.mcmeta"); } plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/flame_elytra.png"); - plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/broken_flame_elytra.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/flame_elytra_broken.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/entity/equipment/wings/flame_elytra.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/cap.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/models/item/custom/cap.json"); @@ -580,7 +621,8 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/resourcepack/assets/minecraft/models/block/custom/magma_plant_stage_3.json"); } - private void updateCachedConfigFiles() { + @Override + public void updateCachedConfigFiles() { Map previousFiles = this.cachedConfigFiles; this.cachedConfigFiles = new HashMap<>(64, 0.5f); for (Pack pack : loadedPacks()) { @@ -643,25 +685,26 @@ public abstract class AbstractPackManager implements PackManager { } private void loadResourceConfigs(Predicate predicate) { - long o1 = System.nanoTime(); - this.updateCachedConfigFiles(); - long o2 = System.nanoTime(); - this.plugin.logger().info("Loaded packs. Took " + String.format("%.2f", ((o2 - o1) / 1_000_000.0)) + " ms"); for (ConfigParser parser : this.sortedParsers) { if (!predicate.test(parser)) { - parser.clear(); continue; } long t1 = System.nanoTime(); parser.preProcess(); parser.loadAll(); parser.postProcess(); - parser.clear(); long t2 = System.nanoTime(); this.plugin.logger().info("Loaded " + parser.sectionId()[0] + " in " + String.format("%.2f", ((t2 - t1) / 1_000_000.0)) + " ms"); } } + @Override + public void clearResourceConfigs() { + for (ConfigParser parser : this.sortedParsers) { + parser.clear(); + } + } + private void processConfigEntry(Map.Entry entry, Path path, Pack pack, BiConsumer callback) { if (entry.getValue() instanceof Map typeSections0) { String key = entry.getKey(); @@ -1570,7 +1613,8 @@ public abstract class AbstractPackManager implements PackManager { JsonObject textures = sourceModelJson.get("textures").getAsJsonObject(); for (Map.Entry entry : textures.entrySet()) { String value = entry.getValue().getAsString(); - if (value.charAt(0) == '#') continue; + // fixme 应该报错,这个影响资源包加载 + if (value.isEmpty() || value.charAt(0) == '#') continue; Key textureResourceLocation = Key.from(value); imageToModels.put(textureResourceLocation, sourceModelLocation); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java index df44b1845..2883c6f6c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/PackManager.java @@ -9,12 +9,13 @@ import org.jetbrains.annotations.NotNull; import java.io.IOException; import java.nio.file.Path; import java.util.Collection; +import java.util.function.Predicate; public interface PackManager extends Manageable { ConfigParser parser(); - void loadResources(boolean recipe); + void loadResources(Predicate predicate); void initCachedAssets(); @@ -37,6 +38,12 @@ public interface PackManager extends Manageable { } } + void loadPacks(); + + void updateCachedConfigFiles(); + + void clearResourceConfigs(); + void generateResourcePack() throws IOException; Path resourcePackPath(); 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 49ad8ec7a..ed9117060 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 @@ -8,6 +8,7 @@ import net.momirealms.craftengine.core.pack.revision.Revision; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MinecraftVersion; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; import java.util.ArrayList; import java.util.List; @@ -80,11 +81,11 @@ public class ConditionItemModel implements ItemModel { @Override public ItemModel create(Map arguments) { ConditionProperty property = ConditionProperties.fromMap(arguments); - ItemModel onTrue = ItemModels.fromObj(arguments.get("on-true")); + ItemModel onTrue = ItemModels.fromObj(ResourceConfigUtils.get(arguments, "on-true", "on_true")); if (onTrue == null) { throw new LocalizedResourceConfigException("warning.config.item.model.condition.missing_on_true"); } - ItemModel onFalse = ItemModels.fromObj(arguments.get("on-false")); + ItemModel onFalse = ItemModels.fromObj(ResourceConfigUtils.get(arguments, "on-false", "on_false")); if (onFalse == null) { throw new LocalizedResourceConfigException("warning.config.item.model.condition.missing_on_false"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/simplified/BowModelReader.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/simplified/BowModelReader.java new file mode 100644 index 000000000..63b78c189 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/simplified/BowModelReader.java @@ -0,0 +1,112 @@ +package net.momirealms.craftengine.core.pack.model.simplified; + +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.util.Key; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Map; + +public class BowModelReader implements SimplifiedModelReader { + public static final BowModelReader INSTANCE = new BowModelReader(); + + @Override + public @Nullable Map convert(List textures, List optionalModelPaths, Key id) { + if (textures.size() != 4) { + throw new LocalizedResourceConfigException("warning.config.item.simplified_model.invalid_texture", "4", String.valueOf(textures.size())); + } + boolean autoModel = optionalModelPaths.isEmpty(); + if (!autoModel && optionalModelPaths.size() != 4) { + throw new LocalizedResourceConfigException("warning.config.item.simplified_model.invalid_model", "4", String.valueOf(optionalModelPaths.size())); + } + return Map.of( + "type", "condition", + "property", "using_item", + "on-false", Map.of( + "path", autoModel ? id.namespace() + ":item/" + id.value() : optionalModelPaths.get(0), + "generation", Map.of( + "parent", "item/bow", + "textures", Map.of( + "layer0", textures.get(0) + ) + ) + ), + "on-true", Map.of( + "type", "range_dispatch", + "property", "use_duration", + "scale", 0.05, + "entries", List.of( + Map.of( + "model", Map.of( + "path", autoModel ? id.namespace() + ":item/" + id.value() + "_pulling_1" : optionalModelPaths.get(2), + "generation", Map.of( + "parent", "item/bow_pulling_1", + "textures", Map.of( + "layer0", textures.get(2) + ) + ) + ), + "threshold", 0.65 + ), + Map.of( + "model", Map.of( + "path", autoModel ? id.namespace() + ":item/" + id.value() + "_pulling_2" : optionalModelPaths.get(3), + "generation", Map.of( + "parent", "item/bow_pulling_2", + "textures", Map.of( + "layer0", textures.get(3) + ) + ) + ), + "threshold", 0.9 + ) + ), + "fallback", Map.of( + "path", autoModel ? id.namespace() + ":item/" + id.value() + "_pulling_0" : optionalModelPaths.get(1), + "generation", Map.of( + "parent", "item/bow_pulling_0", + "textures", Map.of( + "layer0", textures.get(1) + ) + ) + ) + ) + ); + } + + @Override + public @Nullable Map convert(List models) { + if (models.size() != 4) { + throw new LocalizedResourceConfigException("warning.config.item.simplified_model.invalid_model", "4", String.valueOf(models.size())); + } + return Map.of( + "type", "condition", + "property", "using_item", + "on-false", Map.of( + "path", models.get(0) + ), + "on-true", Map.of( + "type", "range_dispatch", + "property", "use_duration", + "scale", 0.05, + "entries", List.of( + Map.of( + "model", Map.of( + "path", models.get(2) + ), + "threshold", 0.65 + ), + Map.of( + "model", Map.of( + "path", models.get(3) + ), + "threshold", 0.9 + ) + ), + "fallback", Map.of( + "path", models.get(1) + ) + ) + ); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/simplified/ConditionModelReader.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/simplified/ConditionModelReader.java new file mode 100644 index 000000000..28a15a4eb --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/simplified/ConditionModelReader.java @@ -0,0 +1,76 @@ +package net.momirealms.craftengine.core.pack.model.simplified; + +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.util.Key; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Map; + +public class ConditionModelReader implements SimplifiedModelReader { + public static final ConditionModelReader FISHING_ROD = new ConditionModelReader("fishing_rod", "fishing_rod/cast", "_cast"); + public static final ConditionModelReader ELYTRA = new ConditionModelReader("generated", "broken", "_broken"); + public static final ConditionModelReader SHIELD = new ConditionModelReader("", "using_item", "_blocking"); + private final String model; + private final String property; + private final String suffix; + + public ConditionModelReader(String model, String property, String suffix) { + this.model = model; + this.property = property; + this.suffix = suffix; + } + + @Override + public @Nullable Map convert(List textures, List optionalModelPaths, Key id) { + if (this.model.isEmpty()) { + return null; + } + if (textures.size() != 2) { + throw new LocalizedResourceConfigException("warning.config.item.simplified_model.invalid_texture", "2", String.valueOf(textures.size())); + } + boolean autoModel = optionalModelPaths.isEmpty(); + if (!autoModel && optionalModelPaths.size() != 2) { + throw new LocalizedResourceConfigException("warning.config.item.simplified_model.invalid_model", "2", String.valueOf(optionalModelPaths.size())); + } + return Map.of( + "type", "condition", + "property", this.property, + "on-false", Map.of( + "path", autoModel ? id.namespace() + ":item/" + id.value() : optionalModelPaths.getFirst(), + "generation", Map.of( + "parent", "item/" + this.model, + "textures", Map.of( + "layer0", textures.getFirst() + ) + ) + ), + "on-true", Map.of( + "path", autoModel ? id.namespace() + ":item/" + id.value() + this.suffix : optionalModelPaths.getLast(), + "generation", Map.of( + "parent", "item/" + this.model, + "textures", Map.of( + "layer0", textures.getLast() + ) + ) + ) + ); + } + + @Override + public @Nullable Map convert(List models) { + if (models.size() != 2) { + throw new LocalizedResourceConfigException("warning.config.item.simplified_model.invalid_model", "2", String.valueOf(models.size())); + } + return Map.of( + "type", "condition", + "property", this.property, + "on-false", Map.of( + "path", models.getFirst() + ), + "on-true", Map.of( + "path", models.getLast() + ) + ); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/simplified/CrossbowModelReader.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/simplified/CrossbowModelReader.java new file mode 100644 index 000000000..0c539e21b --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/simplified/CrossbowModelReader.java @@ -0,0 +1,170 @@ +package net.momirealms.craftengine.core.pack.model.simplified; + +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.util.Key; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Map; + +public class CrossbowModelReader implements SimplifiedModelReader { + public static final CrossbowModelReader INSTANCE = new CrossbowModelReader(); + + @Override + public @Nullable Map convert(List textures, List optionalModelPaths, Key id) { + if (textures.size() != 6) { + throw new LocalizedResourceConfigException("warning.config.item.simplified_model.invalid_texture", "6", String.valueOf(textures.size())); + } + boolean autoModel = optionalModelPaths.isEmpty(); + if (!autoModel && optionalModelPaths.size() != 6) { + throw new LocalizedResourceConfigException("warning.config.item.simplified_model.invalid_model", "6", String.valueOf(optionalModelPaths.size())); + } + return Map.of( + "type", "condition", + "property", "using_item", + "on-false", Map.of( + "type", "select", + "property", "charge_type", + "cases", List.of( + Map.of( + "when", "arrow", + "model", Map.of( + "type", "model", + "path", autoModel ? id.namespace() + ":item/" + id.value() + "_arrow" : optionalModelPaths.get(4), + "generation", Map.of( + "parent", "item/crossbow_arrow", + "textures", Map.of( + "layer0", textures.get(4) + ) + ) + ) + ), + Map.of( + "when", "rocket", + "model", Map.of( + "type", "model", + "path", autoModel ? id.namespace() + ":item/" + id.value() + "_firework" : optionalModelPaths.get(5), + "generation", Map.of( + "parent", "item/crossbow_firework", + "textures", Map.of( + "layer0", textures.get(5) + ) + ) + ) + ) + ), + "fallback", Map.of( + "type", "model", + "path", autoModel ? id.namespace() + ":item/" + id.value() : optionalModelPaths.get(0), + "generation", Map.of( + "parent", "item/crossbow", + "textures", Map.of( + "layer0", textures.get(0) + ) + ) + ) + ), + "on-true", Map.of( + "type", "range_dispatch", + "property", "crossbow/pull", + "entries", List.of( + Map.of( + "model", Map.of( + "type", "model", + "path", autoModel ? id.namespace() + ":item/" + id.value() + "_pulling_1" : optionalModelPaths.get(2), + "generation", Map.of( + "parent", "item/crossbow_pulling_1", + "textures", Map.of( + "layer0", textures.get(2) + ) + ) + ), + "threshold", 0.58 + ), + Map.of( + "model", Map.of( + "type", "model", + "path", autoModel ? id.namespace() + ":item/" + id.value() + "_pulling_2" : optionalModelPaths.get(3), + "generation", Map.of( + "parent", "item/crossbow_pulling_2", + "textures", Map.of( + "layer0", textures.get(3) + ) + ) + ), + "threshold", 1.0 + ) + ), + "fallback", Map.of( + "type", "model", + "path", autoModel ? id.namespace() + ":item/" + id.value() + "_pulling_0" : optionalModelPaths.get(1), + "generation", Map.of( + "parent", "item/crossbow_pulling_0", + "textures", Map.of( + "layer0", textures.get(1) + ) + ) + ) + ) + ); + } + + @Override + public @Nullable Map convert(List models) { + if (models.size() != 6) { + throw new LocalizedResourceConfigException("warning.config.item.simplified_model.invalid_model", "6", String.valueOf(models.size())); + } + return Map.of( + "type", "condition", + "property", "using_item", + "on-false", Map.of( + "type", "select", + "property", "charge_type", + "cases", List.of( + Map.of( + "when", "arrow", + "model", Map.of( + "type", "model", + "path", models.get(4) + ) + ), + Map.of( + "when", "rocket", + "model", Map.of( + "type", "model", + "path", models.get(5) + ) + ) + ), + "fallback", Map.of( + "type", "model", + "path", models.get(0) + ) + ), + "on-true", Map.of( + "type", "range_dispatch", + "property", "crossbow/pull", + "entries", List.of( + Map.of( + "model", Map.of( + "type", "model", + "path", models.get(2) + ), + "threshold", 0.58 + ), + Map.of( + "model", Map.of( + "type", "model", + "path", models.get(3) + ), + "threshold", 1.0 + ) + ), + "fallback", Map.of( + "type", "model", + "path", models.get(1) + ) + ) + ); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/simplified/GeneratedModelReader.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/simplified/GeneratedModelReader.java new file mode 100644 index 000000000..d28c24325 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/simplified/GeneratedModelReader.java @@ -0,0 +1,62 @@ +package net.momirealms.craftengine.core.pack.model.simplified; + +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.util.Key; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class GeneratedModelReader implements SimplifiedModelReader { + public static final GeneratedModelReader GENERATED = new GeneratedModelReader("generated"); + public static final GeneratedModelReader HANDHELD = new GeneratedModelReader("handheld"); + + private final String model; + + public GeneratedModelReader(String model) { + this.model = model; + } + + @Override + public Map convert(List textures, List optionalModelPaths, Key id) { + if (optionalModelPaths.size() >= 2) { + throw new LocalizedResourceConfigException("warning.config.item.simplified_model.invalid_model", "1", String.valueOf(optionalModelPaths.size())); + } + boolean autoModelPath = optionalModelPaths.size() != 1; + Map texturesProperty; + switch (textures.size()) { + case 1 -> texturesProperty = Map.of("layer0", textures.getFirst()); + case 2 -> texturesProperty = Map.of( + "layer0", textures.get(0), + "layer1", textures.get(1) + ); + default -> { + texturesProperty = new HashMap<>(); + for (int i = 0; i < textures.size(); i++) { + texturesProperty.put("layer" + i, textures.get(i)); + } + } + } + return Map.of( + "type", "model", + "path", autoModelPath ? id.namespace() + ":item/" + id.value() : optionalModelPaths.getFirst(), + "generation", Map.of( + "parent", "item/" + this.model, + "textures", texturesProperty + ) + ); + } + + @Override + public @Nullable Map convert(List optionalModelPaths) { + if (optionalModelPaths.size() >= 2) { + return Map.of( + "type", "composite", + "models", optionalModelPaths + ); + } else { + return Map.of("path", optionalModelPaths.getFirst()); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/model/simplified/SimplifiedModelReader.java b/core/src/main/java/net/momirealms/craftengine/core/pack/model/simplified/SimplifiedModelReader.java new file mode 100644 index 000000000..512d066d1 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/model/simplified/SimplifiedModelReader.java @@ -0,0 +1,16 @@ +package net.momirealms.craftengine.core.pack.model.simplified; + +import net.momirealms.craftengine.core.util.Key; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Map; + +public interface SimplifiedModelReader { + + @Nullable + Map convert(List textures, List optionalModelPaths, Key id); + + @Nullable + Map convert(List models); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java index 918c4dcb5..750f04f10 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java @@ -12,6 +12,7 @@ import net.momirealms.craftengine.core.item.recipe.network.legacy.LegacyRecipeTy import net.momirealms.craftengine.core.item.recipe.network.modern.display.RecipeDisplayTypes; import net.momirealms.craftengine.core.item.recipe.network.modern.display.slot.SlotDisplayTypes; import net.momirealms.craftengine.core.loot.VanillaLootManager; +import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.PackManager; import net.momirealms.craftengine.core.plugin.classpath.ClassPathAppender; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; @@ -30,6 +31,7 @@ import net.momirealms.craftengine.core.plugin.gui.GuiManager; import net.momirealms.craftengine.core.plugin.gui.category.ItemBrowserManager; import net.momirealms.craftengine.core.plugin.gui.category.ItemBrowserManagerImpl; import net.momirealms.craftengine.core.plugin.locale.TranslationManager; +import net.momirealms.craftengine.core.plugin.locale.TranslationManagerImpl; import net.momirealms.craftengine.core.plugin.logger.PluginLogger; import net.momirealms.craftengine.core.plugin.logger.filter.DisconnectLogFilter; import net.momirealms.craftengine.core.plugin.logger.filter.LogFilter; @@ -79,8 +81,8 @@ public abstract class CraftEngine implements Plugin { protected ProjectileManager projectileManager; protected SeatManager seatManager; - private final PluginTaskRegistry preLoadTaskRegistry = new PluginTaskRegistry(); - private final PluginTaskRegistry postLoadTaskRegistry = new PluginTaskRegistry(); + private final PluginTaskRegistry beforeEnableTaskRegistry = new PluginTaskRegistry(); + private final PluginTaskRegistry afterEnableTaskRegistry = new PluginTaskRegistry(); private final Consumer reloadEventDispatcher; private boolean isReloading; @@ -110,6 +112,24 @@ public abstract class CraftEngine implements Plugin { RecipeDisplayTypes.init(); SlotDisplayTypes.init(); LegacyRecipeTypes.init(); + + // 初始化模板管理器 + this.templateManager = new TemplateManagerImpl(); + // 初始化全局变量管理器 + this.globalVariableManager = new GlobalVariableManager(); + // 初始化物品浏览器 + this.itemBrowserManager = new ItemBrowserManagerImpl(this); + } + + public void setUpConfigAndLocale() { + this.config = new Config(this); + this.config.updateConfigCache(); + // 先读取语言后,再重载语言文件系统 + this.config.loadForcedLocale(); + this.translationManager = new TranslationManagerImpl(this); + this.translationManager.reload(); + // 最后才加载完整的config配置 + this.config.loadFullSettings(); } public record ReloadResult(boolean success, long asyncTime, long syncTime) { @@ -123,6 +143,48 @@ public abstract class CraftEngine implements Plugin { } } + private void reloadManagers() { + this.templateManager.reload(); + this.globalVariableManager.reload(); + this.furnitureManager.reload(); + this.fontManager.reload(); + this.itemManager.reload(); + this.soundManager.reload(); + this.itemBrowserManager.reload(); + this.blockManager.reload(); + this.worldManager.reload(); + this.vanillaLootManager.reload(); + this.guiManager.reload(); + this.packManager.reload(); + this.advancementManager.reload(); + this.projectileManager.reload(); + this.seatManager.reload(); + } + + private void runDelayTasks(boolean reloadRecipe) { + List> delayedLoadTasks = new ArrayList<>(); + // 指令补全,重置外部配方原料 + delayedLoadTasks.add(CompletableFuture.runAsync(() -> this.itemManager.delayedLoad(), this.scheduler.async())); + // 重置映射表,指令补全,发送tags,收集声音 + delayedLoadTasks.add(CompletableFuture.runAsync(() -> this.blockManager.delayedLoad(), this.scheduler.async())); + // 处理block_name特殊语言键 + delayedLoadTasks.add(CompletableFuture.runAsync(() -> this.translationManager.delayedLoad(), this.scheduler.async())); + // 指令补全 + delayedLoadTasks.add(CompletableFuture.runAsync(() -> this.furnitureManager.delayedLoad(), this.scheduler.async())); + // 处理外部category,加载ui常量 + delayedLoadTasks.add(CompletableFuture.runAsync(() -> this.itemBrowserManager.delayedLoad(), this.scheduler.async())); + // 收集非法字符,构造前缀树,指令补全 + delayedLoadTasks.add(CompletableFuture.runAsync(() -> this.fontManager.delayedLoad(), this.scheduler.async())); + // 指令补全 + delayedLoadTasks.add(CompletableFuture.runAsync(() -> this.soundManager.delayedLoad(), this.scheduler.async())); + // 如果重载配方 + if (reloadRecipe) { + // 转换数据包配方 + delayedLoadTasks.add(CompletableFuture.runAsync(() -> this.recipeManager.delayedLoad(), this.scheduler.async())); + } + CompletableFutures.allOf(delayedLoadTasks).join(); + } + public CompletableFuture reloadPlugin(Executor asyncExecutor, Executor syncExecutor, boolean reloadRecipe) { CompletableFuture future = new CompletableFuture<>(); asyncExecutor.execute(() -> { @@ -134,56 +196,26 @@ public abstract class CraftEngine implements Plugin { } this.isReloading = true; long time1 = System.currentTimeMillis(); - // firstly reload main config + // 重载config this.config.load(); - // now we reload the translations + // 重载翻译 this.translationManager.reload(); - // clear the outdated cache by reloading the managers - this.templateManager.reload(); - this.globalVariableManager.reload(); - this.furnitureManager.reload(); - this.fontManager.reload(); - this.itemManager.reload(); - this.soundManager.reload(); - this.itemBrowserManager.reload(); - this.blockManager.reload(); - this.worldManager.reload(); - this.vanillaLootManager.reload(); - this.guiManager.reload(); - this.packManager.reload(); - this.advancementManager.reload(); - this.projectileManager.reload(); - this.seatManager.reload(); + // 重载其他管理器 + this.reloadManagers(); if (reloadRecipe) { this.recipeManager.reload(); } try { - // now we load resources - this.packManager.loadResources(reloadRecipe); + // 加载全部配置资源 + this.packManager.loadPacks(); + this.packManager.updateCachedConfigFiles(); + this.packManager.loadResources(reloadRecipe ? (p) -> true : (p) -> p.loadingSequence() != LoadingSequence.RECIPE); + this.packManager.clearResourceConfigs(); } catch (Exception e) { this.logger().warn("Failed to load resources folder", e); } - List> delayedLoadTasks = new ArrayList<>(); - // 指令补全,重置外部配方原料 - delayedLoadTasks.add(CompletableFuture.runAsync(() -> this.itemManager.delayedLoad(), this.scheduler.async())); - // 重置映射表,指令补全,发送tags,收集声音 - delayedLoadTasks.add(CompletableFuture.runAsync(() -> this.blockManager.delayedLoad(), this.scheduler.async())); - // 处理block_name特殊语言键 - delayedLoadTasks.add(CompletableFuture.runAsync(() -> this.translationManager.delayedLoad(), this.scheduler.async())); - // 指令补全 - delayedLoadTasks.add(CompletableFuture.runAsync(() -> this.furnitureManager.delayedLoad(), this.scheduler.async())); - // 处理外部category,加载ui常量 - delayedLoadTasks.add(CompletableFuture.runAsync(() -> this.itemBrowserManager.delayedLoad(), this.scheduler.async())); - // 收集非法字符,构造前缀树,指令补全 - delayedLoadTasks.add(CompletableFuture.runAsync(() -> this.fontManager.delayedLoad(), this.scheduler.async())); - // 指令补全 - delayedLoadTasks.add(CompletableFuture.runAsync(() -> this.soundManager.delayedLoad(), this.scheduler.async())); - // 如果重载配方 - if (reloadRecipe) { - // 转换数据包配方 - delayedLoadTasks.add(CompletableFuture.runAsync(() -> this.recipeManager.delayedLoad(), this.scheduler.async())); - } - CompletableFutures.allOf(delayedLoadTasks).join(); + // 执行延迟任务 + this.runDelayTasks(reloadRecipe); // 重新发送tags,需要等待tags更新完成 this.networkManager.delayedLoad(); long time2 = System.currentTimeMillis(); @@ -193,9 +225,9 @@ public abstract class CraftEngine implements Plugin { syncExecutor.execute(() -> { try { long time3 = System.currentTimeMillis(); - // register songs + // 注册唱片机音乐 this.soundManager.runDelayedSyncTasks(); - // register recipes + // 同步注册配方 if (reloadRecipe) { this.recipeManager.runDelayedSyncTasks(); } @@ -214,43 +246,84 @@ public abstract class CraftEngine implements Plugin { protected void onPluginEnable() { this.isInitializing = true; + + // 注册网络相关的bukkit事件监听器 this.networkManager.init(); - this.templateManager = new TemplateManagerImpl(); - this.globalVariableManager = new GlobalVariableManager(); - this.itemBrowserManager = new ItemBrowserManagerImpl(this); + // 注册指令 this.commandManager.registerDefaultFeatures(); - // delay the reload so other plugins can register some custom parsers + // 注册物品相关的事件监听器 + this.itemManager.delayedInit(); + // 注册方块相关的事件监听器 + this.blockManager.delayedInit(); + // 注册容器相关的监听器 + this.guiManager.delayedInit(); + // 注册配方相关的监听器 + this.recipeManager.delayedInit(); + // 注册数据包状态的监听器 + this.packManager.delayedInit(); + // 注册聊天监听器 + this.fontManager.delayedInit(); + // 注册实体死亡监听器 + this.vanillaLootManager.delayedInit(); + // 注册脱离坐骑监听器 + this.seatManager.delayedInit(); + // 注册世界加载相关监听器 + this.worldManager.delayedInit(); + + // 延迟任务 + this.beforeEnableTaskRegistry.executeTasks(); + + if (!Config.delayConfigurationLoad()) { + // 清理缓存,初始化一些东西,不需要读config和translation,因为boostrap阶段已经读取过了 + this.reloadManagers(); + // 加载packs + this.packManager.loadPacks(); + this.packManager.updateCachedConfigFiles(); + // 不要加载配方 + this.packManager.loadResources((p) -> p.loadingSequence() != LoadingSequence.RECIPE); + this.runDelayTasks(false); + } + + // 延迟任务 + this.afterEnableTaskRegistry.executeTasks(); + + // 延迟重载,以便其他依赖CraftEngine的插件能注册parser this.scheduler.sync().runDelayed(() -> { - this.preLoadTaskRegistry.executeTasks(); - this.registerDefaultParsers(); - // hook external item plugins - this.itemManager.delayedInit(); - // hook worldedit - this.blockManager.delayedInit(); - // register listeners and tasks - this.guiManager.delayedInit(); - this.recipeManager.delayedInit(); - this.packManager.delayedInit(); - this.fontManager.delayedInit(); - this.vanillaLootManager.delayedInit(); - this.advancementManager.delayedInit(); - this.seatManager.delayedInit(); - this.compatibilityManager.onDelayedEnable(); - // reload the plugin - try { - this.reloadPlugin(Runnable::run, Runnable::run, true); - } catch (Exception e) { - this.logger.warn("Failed to reload plugin on enable stage", e); - } - // must be after reloading because this process loads furniture - this.projectileManager.delayedInit(); - this.worldManager.delayedInit(); - this.furnitureManager.delayedInit(); - // set up some platform extra tasks + // 初始化一些平台的任务 this.platformDelayedEnable(); + + // 延迟兼容性任务,比如物品库的支持。保证后续配方正确加载 + this.compatibilityManager.onDelayedEnable(); + + if (!Config.delayConfigurationLoad()) { + // 单独加载配方 + this.recipeManager.reload(); + this.packManager.loadResources((p) -> p.loadingSequence() == LoadingSequence.RECIPE); + this.recipeManager.delayedLoad(); + this.packManager.clearResourceConfigs(); + // 重新发送tags,需要等待tags更新完成 + this.networkManager.delayedLoad(); + // 注册唱片机音乐 + this.soundManager.runDelayedSyncTasks(); + // 同步注册配方 + this.recipeManager.runDelayedSyncTasks(); + } else { + try { + this.reloadPlugin(Runnable::run, Runnable::run, true); + } catch (Exception e) { + this.logger.severe("Failed to reload plugin on delayed enable stage", e); + } + } + + // 必须要在完整重载后再初始化,否则会因为配置不存在,导致家具、弹射物等无法正确被加载 + this.projectileManager.delayedInit(); + this.furnitureManager.delayedInit(); + // 完成初始化 this.isInitializing = false; - this.postLoadTaskRegistry.executeTasks(); + // 异步去缓存资源包相关文件 this.scheduler.executeAsync(() -> this.packManager.initCachedAssets()); + // 正式完成重载 + this.reloadEventDispatcher.accept(this); }); } @@ -490,13 +563,27 @@ public abstract class CraftEngine implements Plugin { return platform; } + /** + * + * This task registry allows you to schedule tasks to run before CraftEngine enable, without dealing with plugin dependencies. + * You must register these tasks during the onLoad phase; otherwise, they will not be executed. + * + * @return PluginTaskRegistry + */ @ApiStatus.Experimental - public PluginTaskRegistry preLoadTaskRegistry() { - return preLoadTaskRegistry; + public PluginTaskRegistry beforeEnableTaskRegistry() { + return beforeEnableTaskRegistry; } + /** + * + * This task registry allows you to schedule tasks to run after CraftEngine enable, without dealing with plugin dependencies. + * You must register these tasks during the onLoad phase; otherwise, they will not be executed. + * + * @return PluginTaskRegistry + */ @ApiStatus.Experimental - public PluginTaskRegistry postLoadTaskRegistry() { - return postLoadTaskRegistry; + public PluginTaskRegistry afterEnableTaskRegistry() { + return afterEnableTaskRegistry; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/Manageable.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/Manageable.java index d8ae4d046..09bfa780b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/Manageable.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/Manageable.java @@ -2,7 +2,6 @@ package net.momirealms.craftengine.core.plugin; public interface Manageable { - // on plugin enable default void init() { } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java index ce0e42ee9..76ff553a7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java @@ -47,6 +47,7 @@ public class Config { protected boolean metrics; protected boolean filterConfigurationPhaseDisconnect; protected Locale forcedLocale; + protected boolean delayConfigurationLoad; protected boolean debug$common; protected boolean debug$packet; @@ -175,6 +176,7 @@ public class Config { protected boolean network$intercept_packets$set_score; protected boolean network$intercept_packets$item; protected boolean network$intercept_packets$advancement; + protected boolean network$intercept_packets$player_chat; protected boolean network$disable_item_operations; protected boolean item$client_bound_model; @@ -287,6 +289,7 @@ public class Config { public void loadFullSettings() { YamlDocument config = settings(); forcedLocale = TranslationManager.parseLocale(config.getString("forced-locale", "")); + delayConfigurationLoad = config.getBoolean("delay-configuration-load", false); // basics metrics = config.getBoolean("metrics", false); @@ -546,6 +549,7 @@ public class Config { network$intercept_packets$set_score = config.getBoolean("network.intercept-packets.set-score", true); network$intercept_packets$item = config.getBoolean("network.intercept-packets.item", true); network$intercept_packets$advancement = config.getBoolean("network.intercept-packets.advancement", true); + network$intercept_packets$player_chat = config.getBoolean("network.intercept-packets.player-chat", true); // emoji emoji$contexts$chat = config.getBoolean("emoji.contexts.chat", true); @@ -575,6 +579,10 @@ public class Config { return instance.configVersion; } + public static boolean delayConfigurationLoad() { + return instance.delayConfigurationLoad; + } + public static boolean debugCommon() { return instance.debug$common; } @@ -980,6 +988,10 @@ public class Config { return instance.network$intercept_packets$advancement; } + public static boolean interceptPlayerChat() { + return instance.network$intercept_packets$player_chat; + } + public static boolean predictBreaking() { return instance.block$predict_breaking; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchBlockCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchBlockCondition.java index a26f015e2..9eee31c0c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchBlockCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchBlockCondition.java @@ -40,7 +40,7 @@ public class MatchBlockCondition implements Condition Optional optionalWorldPosition = ctx.getOptionalParameter(DirectContextParameters.POSITION); if (optionalWorldPosition.isPresent()) { World world = optionalWorldPosition.get().world(); - ExistingBlock blockAt = world.getBlockAt(MiscUtils.fastFloor(this.x.getDouble(ctx)), MiscUtils.fastFloor(this.y.getDouble(ctx)), MiscUtils.fastFloor(this.z.getDouble(ctx))); + ExistingBlock blockAt = world.getBlock(MiscUtils.fastFloor(this.x.getDouble(ctx)), MiscUtils.fastFloor(this.y.getDouble(ctx)), MiscUtils.fastFloor(this.z.getDouble(ctx))); return MiscUtils.matchRegex(blockAt.id().asString(), this.ids, this.regexMatch); } return false; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java index 74592b40a..447ce05f0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java @@ -54,6 +54,7 @@ public class EventFunctions { register(CommonFunctions.ALTERNATIVES, new IfElseFunction.FactoryImpl<>(EventConditions::fromMap, EventFunctions::fromMap)); register(CommonFunctions.WHEN, new WhenFunction.FactoryImpl<>(EventConditions::fromMap, EventFunctions::fromMap)); register(CommonFunctions.DAMAGE_ITEM, new DamageItemFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.CYCLE_BLOCK_PROPERTY, new CycleBlockPropertyFunction.FactoryImpl<>(EventConditions::fromMap)); } public static void register(Key key, FunctionFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java index 5cd4a5d0a..bc638a23d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java @@ -45,4 +45,5 @@ public final class CommonFunctions { public static final Key ALL_OF = Key.of("craftengine:all_of"); public static final Key DUMMY = Key.of("craftengine:dummy"); public static final Key DAMAGE_ITEM = Key.of("craftengine:damage_item"); + public static final Key CYCLE_BLOCK_PROPERTY = Key.of("craftengine:cycle_block_property"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CycleBlockPropertyFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CycleBlockPropertyFunction.java new file mode 100644 index 000000000..358116670 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CycleBlockPropertyFunction.java @@ -0,0 +1,74 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.block.BlockStateWrapper; +import net.momirealms.craftengine.core.block.UpdateOption; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; +import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +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.world.ExistingBlock; +import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.WorldPosition; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class CycleBlockPropertyFunction extends AbstractConditionalFunction { + private final String property; + private final NumberProvider inverse; + private final NumberProvider x; + private final NumberProvider y; + private final NumberProvider z; + private final NumberProvider updateFlags; + + public CycleBlockPropertyFunction(List> predicates, String property, NumberProvider inverse, NumberProvider x, NumberProvider y, NumberProvider z, NumberProvider updateFlags) { + super(predicates); + this.property = property; + this.inverse = inverse; + this.x = x; + this.y = y; + this.z = z; + this.updateFlags = updateFlags; + } + + @Override + protected void runInternal(CTX ctx) { + Optional optionalWorldPosition = ctx.getOptionalParameter(DirectContextParameters.POSITION); + if (optionalWorldPosition.isEmpty()) return; + World world = optionalWorldPosition.get().world(); + int x = MiscUtils.fastFloor(this.x.getDouble(ctx)); + int y = MiscUtils.fastFloor(this.y.getDouble(ctx)); + int z = MiscUtils.fastFloor(this.z.getDouble(ctx)); + ExistingBlock blockAt = world.getBlock(x, y, z); + BlockStateWrapper wrapper = blockAt.blockState().cycleProperty(this.property, this.inverse.getInt(ctx) == 0); + world.setBlockState(x, y, z, wrapper, this.updateFlags.getInt(ctx)); + } + + @Override + public Key type() { + return CommonFunctions.CYCLE_BLOCK_PROPERTY; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + return new CycleBlockPropertyFunction<>(getPredicates(arguments), + ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("property"), "warning.config.function.cycle_block_property.missing_property"), + NumberProviders.fromObject(arguments.getOrDefault("inverse", "")), + NumberProviders.fromObject(arguments.getOrDefault("x", "")), + NumberProviders.fromObject(arguments.getOrDefault("y", "")), + NumberProviders.fromObject(arguments.getOrDefault("z", "")), + Optional.ofNullable(arguments.get("update-flags")).map(NumberProviders::fromObject).orElse(NumberProviders.direct(UpdateOption.UPDATE_ALL.flags()))); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java index 4734cb594..1b6e8bf72 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java @@ -40,7 +40,7 @@ public class PlaceBlockFunction extends AbstractConditional Optional optionalWorldPosition = ctx.getOptionalParameter(DirectContextParameters.POSITION); if (optionalWorldPosition.isPresent()) { World world = optionalWorldPosition.get().world(); - world.setBlockAt(MiscUtils.fastFloor(this.x.getDouble(ctx)), MiscUtils.fastFloor(this.y.getDouble(ctx)), MiscUtils.fastFloor(this.z.getDouble(ctx)), this.lazyBlockState.get(), this.updateFlags.getInt(ctx)); + world.setBlockState(MiscUtils.fastFloor(this.x.getDouble(ctx)), MiscUtils.fastFloor(this.y.getDouble(ctx)), MiscUtils.fastFloor(this.z.getDouble(ctx)), this.lazyBlockState.get(), this.updateFlags.getInt(ctx)); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/TransformBlockFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/TransformBlockFunction.java index 2183d51c6..09da0dc26 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/TransformBlockFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/TransformBlockFunction.java @@ -48,7 +48,7 @@ public class TransformBlockFunction extends AbstractConditi int x = MiscUtils.fastFloor(this.x.getDouble(ctx)); int y = MiscUtils.fastFloor(this.y.getDouble(ctx)); int z = MiscUtils.fastFloor(this.z.getDouble(ctx)); - BlockStateWrapper existingBlockState = world.getBlockAt(x, y, z).blockState().withProperties(this.properties); + BlockStateWrapper existingBlockState = world.getBlock(x, y, z).blockState().withProperties(this.properties); CompoundTag newProperties = new CompoundTag(); for (String propertyName : existingBlockState.getPropertyNames()) { newProperties.putString(propertyName, String.valueOf(existingBlockState.getProperty(propertyName)).toLowerCase(Locale.ROOT)); @@ -58,7 +58,7 @@ public class TransformBlockFunction extends AbstractConditi newProperties.put(tagEntry.getKey(), tagEntry.getValue()); } } - world.setBlockAt(x, y, z, this.lazyBlockState.get().withProperties(newProperties), this.updateFlags.getInt(ctx)); + world.setBlockState(x, y, z, this.lazyBlockState.get().withProperties(newProperties), this.updateFlags.getInt(ctx)); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/UpdateBlockPropertyFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/UpdateBlockPropertyFunction.java index 4993e5465..693647cf5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/UpdateBlockPropertyFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/UpdateBlockPropertyFunction.java @@ -43,9 +43,9 @@ public class UpdateBlockPropertyFunction extends AbstractCo int x = MiscUtils.fastFloor(this.x.getDouble(ctx)); int y = MiscUtils.fastFloor(this.y.getDouble(ctx)); int z = MiscUtils.fastFloor(this.z.getDouble(ctx)); - ExistingBlock blockAt = world.getBlockAt(x, y, z); + ExistingBlock blockAt = world.getBlock(x, y, z); BlockStateWrapper wrapper = blockAt.blockState().withProperties(this.properties); - world.setBlockAt(x, y, z, wrapper, this.updateFlags.getInt(ctx)); + world.setBlockState(x, y, z, wrapper, this.updateFlags.getInt(ctx)); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProviders.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProviders.java index 0b46ffb92..fd636b1c7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProviders.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProviders.java @@ -64,6 +64,8 @@ public class NumberProviders { } if (object instanceof Number number) { return new FixedNumberProvider(number.floatValue()); + } else if (object instanceof Boolean bool) { + return new FixedNumberProvider(bool ? 1 : 0); } else if (object instanceof Map map) { return fromMap((Map) map); } else { diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/FriendlyByteBuf.java b/core/src/main/java/net/momirealms/craftengine/core/util/FriendlyByteBuf.java index b4b339108..09e4a4603 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/FriendlyByteBuf.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/FriendlyByteBuf.java @@ -74,6 +74,16 @@ public class FriendlyByteBuf extends ByteBuf { this.writeLong(instant.toEpochMilli()); } + public static IntFunction limitValue(IntFunction applier, int max) { + return (j) -> { + if (j > max) { + throw new DecoderException("Value " + j + " is larger than limit " + max); + } else { + return applier.apply(j); + } + }; + } + public > C readCollection(IntFunction collectionFactory, Reader reader) { int i = this.readVarInt(); C collection = collectionFactory.apply(i); @@ -495,12 +505,12 @@ public class FriendlyByteBuf extends ByteBuf { return this; } - public FriendlyByteBuf writeNbt(@Nullable Tag compound, boolean named) { - if (compound == null) { + public FriendlyByteBuf writeNbt(@Nullable Tag tag, boolean named) { + if (tag == null) { this.writeByte(0); } else { try { - NBT.writeUnnamedTag(compound, new ByteBufOutputStream(this), named); + NBT.writeUnnamedTag(tag, new ByteBufOutputStream(this), named); } catch (IOException e) { throw new EncoderException("Failed to write NBT compound: " + e.getMessage(), e); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/VersionHelper.java b/core/src/main/java/net/momirealms/craftengine/core/util/VersionHelper.java index 65acf2db1..633dcba99 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/VersionHelper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/VersionHelper.java @@ -8,7 +8,7 @@ import java.nio.charset.StandardCharsets; import java.util.Objects; public class VersionHelper { - public static final boolean PREMIUM = false; + public static final boolean PREMIUM = true; public static final MinecraftVersion MINECRAFT_VERSION; public static final boolean COMPONENT_RELEASE; private static final int version; diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/BlockAccessor.java b/core/src/main/java/net/momirealms/craftengine/core/world/BlockAccessor.java new file mode 100644 index 000000000..b9386567e --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/BlockAccessor.java @@ -0,0 +1,4 @@ +package net.momirealms.craftengine.core.world; + +public interface BlockAccessor extends BlockGetter, BlockSetter, WorldHeightAccessor { +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/BlockGetter.java b/core/src/main/java/net/momirealms/craftengine/core/world/BlockGetter.java new file mode 100644 index 000000000..66ad66f27 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/BlockGetter.java @@ -0,0 +1,12 @@ +package net.momirealms.craftengine.core.world; + +import net.momirealms.craftengine.core.block.BlockStateWrapper; + +public interface BlockGetter { + + BlockStateWrapper getBlockState(int x, int y, int z); + + default BlockStateWrapper getBlockState(BlockPos pos) { + return getBlockState(pos.x, pos.y, pos.z); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/BlockSetter.java b/core/src/main/java/net/momirealms/craftengine/core/world/BlockSetter.java new file mode 100644 index 000000000..b3c797fe0 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/BlockSetter.java @@ -0,0 +1,21 @@ +package net.momirealms.craftengine.core.world; + +import net.momirealms.craftengine.core.block.BlockStateWrapper; +import net.momirealms.craftengine.core.block.ImmutableBlockState; + +public interface BlockSetter { + + void setBlockState(int x, int y, int z, BlockStateWrapper blockState, int flags); + + default void setBlockState(int x, int y, int z, ImmutableBlockState blockState, int flags) { + this.setBlockState(x, y, z, blockState.customBlockState(), flags); + } + + default void setBlockState(BlockPos pos, BlockStateWrapper blockState, int flags) { + this.setBlockState(pos.x(), pos.y(), pos.z(), blockState, flags); + } + + default void setBlockState(BlockPos pos, ImmutableBlockState blockState, int flags) { + this.setBlockState(pos.x(), pos.y(), pos.z(), blockState, flags); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/GeneratingWorld.java b/core/src/main/java/net/momirealms/craftengine/core/world/GeneratingWorld.java new file mode 100644 index 000000000..32de794c9 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/GeneratingWorld.java @@ -0,0 +1,6 @@ +package net.momirealms.craftengine.core.world; + +public interface GeneratingWorld extends BlockAccessor, WorldHeightAccessor { + + Object worldGenLevel(); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/World.java b/core/src/main/java/net/momirealms/craftengine/core/world/World.java index c8b94cdc4..b89c0c61c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/World.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/World.java @@ -1,7 +1,5 @@ package net.momirealms.craftengine.core.world; -import net.momirealms.craftengine.core.block.BlockStateWrapper; -import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.Context; @@ -17,7 +15,7 @@ import java.nio.file.Path; import java.util.List; import java.util.UUID; -public interface World { +public interface World extends BlockAccessor { CEWorld storageWorld(); @@ -25,26 +23,10 @@ public interface World { Object serverWorld(); - WorldHeight worldHeight(); + ExistingBlock getBlock(int x, int y, int z); - ExistingBlock getBlockAt(int x, int y, int z); - - default ExistingBlock getBlockAt(final BlockPos pos) { - return getBlockAt(pos.x(), pos.y(), pos.z()); - } - - void setBlockAt(int x, int y, int z, BlockStateWrapper blockState, int flags); - - default void setBlockAt(int x, int y, int z, ImmutableBlockState blockState, int flags) { - this.setBlockAt(x, y, z, blockState.customBlockState(), flags); - } - - default void setBlockAt(BlockPos pos, BlockStateWrapper blockState, int flags) { - this.setBlockAt(pos.x(), pos.y(), pos.z(), blockState, flags); - } - - default void setBlockAt(BlockPos pos, ImmutableBlockState blockState, int flags) { - this.setBlockAt(pos.x(), pos.y(), pos.z(), blockState, flags); + default ExistingBlock getBlock(final BlockPos pos) { + return getBlock(pos.x(), pos.y(), pos.z()); } String name(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/WorldHeight.java b/core/src/main/java/net/momirealms/craftengine/core/world/WorldHeight.java index c5486a74f..9bda642bb 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/WorldHeight.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/WorldHeight.java @@ -63,7 +63,7 @@ public interface WorldHeight { @Override public int getMinBuildHeight() { - return bottomY; + return this.bottomY; } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/WorldHeightAccessor.java b/core/src/main/java/net/momirealms/craftengine/core/world/WorldHeightAccessor.java new file mode 100644 index 000000000..c203674fe --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/WorldHeightAccessor.java @@ -0,0 +1,6 @@ +package net.momirealms.craftengine.core.world; + +public interface WorldHeightAccessor { + + WorldHeight worldHeight(); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java b/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java index d6a746cbd..c20304252 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java @@ -15,7 +15,7 @@ public interface WorldManager extends Manageable { CEWorld[] getWorlds(); - void loadWorld(World world); + CEWorld loadWorld(World world); void loadWorld(CEWorld world); diff --git a/gradle.properties b/gradle.properties index 0ec0adef5..ff17174fc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,15 +1,14 @@ org.gradle.jvmargs=-Xmx1G # Project settings -# Rule: [major update].[feature update].[bug fix] -project_version=0.0.65.6 -config_version=53 -lang_version=37 +project_version=0.0.65.8 +config_version=55 +lang_version=38 project_group=net.momirealms latest_supported_version=1.21.10 # Supported languages -supported_languages=en,zh_cn,zh_tw,es,tr,de,ru_ru +supported_languages=en,zh_cn,zh_tw,es,tr,de,ru_ru,fr_fr # Dependency settings paper_version=1.21.10 @@ -49,7 +48,7 @@ byte_buddy_version=1.17.8 ahocorasick_version=0.6.3 snake_yaml_version=2.5 anti_grief_version=1.0.4 -nms_helper_version=1.0.127 +nms_helper_version=1.0.134 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.34.5