9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-19 15:09:15 +00:00

Merge pull request #464 from Xiao-MoMi/dev

完善数据包相关支持
This commit is contained in:
XiaoMoMi
2025-11-17 15:19:33 +08:00
committed by GitHub
149 changed files with 3981 additions and 1840 deletions

3
.gitmodules vendored
View File

@@ -1,3 +1,6 @@
[submodule "wiki"] [submodule "wiki"]
path = wiki path = wiki
url = https://github.com/Xiao-MoMi/craft-engine-wiki.git 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

View File

@@ -2,11 +2,13 @@ package net.momirealms.craftengine.bukkit.compatibility;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; 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.item.*;
import net.momirealms.craftengine.bukkit.compatibility.legacy.slimeworld.LegacySlimeFormatStorageAdaptor; import net.momirealms.craftengine.bukkit.compatibility.legacy.slimeworld.LegacySlimeFormatStorageAdaptor;
import net.momirealms.craftengine.bukkit.compatibility.leveler.*; 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.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.ModelEngineModel;
import net.momirealms.craftengine.bukkit.compatibility.model.modelengine.ModelEngineUtils; import net.momirealms.craftengine.bukkit.compatibility.model.modelengine.ModelEngineUtils;
import net.momirealms.craftengine.bukkit.compatibility.mythicmobs.MythicItemDropListener; import net.momirealms.craftengine.bukkit.compatibility.mythicmobs.MythicItemDropListener;
@@ -69,15 +71,6 @@ public class BukkitCompatibilityManager implements CompatibilityManager {
@Override @Override
public void onEnable() { public void onEnable() {
this.initSlimeWorldHook(); this.initSlimeWorldHook();
if (this.isPluginEnabled("PlaceholderAPI")) {
PlaceholderAPIUtils.registerExpansions(this.plugin);
this.hasPlaceholderAPI = true;
logHook("PlaceholderAPI");
}
if (this.isPluginEnabled("Skript")) {
SkriptHook.register();
logHook("Skript");
}
// WorldEdit // WorldEdit
// FastAsyncWorldEdit // FastAsyncWorldEdit
if (this.isPluginEnabled("FastAsyncWorldEdit")) { if (this.isPluginEnabled("FastAsyncWorldEdit")) {
@@ -91,16 +84,47 @@ public class BukkitCompatibilityManager implements CompatibilityManager {
this.initWorldEditHook(); this.initWorldEditHook();
logHook("WorldEdit"); 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 @Override
public void onDelayedEnable() { public void onDelayedEnable() {
if (this.isPluginEnabled("PlaceholderAPI")) {
PlaceholderAPIUtils.registerExpansions(this.plugin);
this.hasPlaceholderAPI = true;
logHook("PlaceholderAPI");
}
this.initItemHooks(); this.initItemHooks();
if (this.isPluginEnabled("LuckPerms")) { if (this.isPluginEnabled("LuckPerms")) {
this.initLuckPermsHook(); this.initLuckPermsHook();
logHook("LuckPerms"); logHook("LuckPerms");
} }
if (this.isPluginEnabled("Skript")) {
SkriptHook.register();
logHook("Skript");
}
if (this.isPluginEnabled("AuraSkills")) { if (this.isPluginEnabled("AuraSkills")) {
this.registerLevelerProvider("AuraSkills", new AuraSkillsLevelerProvider()); this.registerLevelerProvider("AuraSkills", new AuraSkillsLevelerProvider());
logHook("AuraSkills"); logHook("AuraSkills");
@@ -133,33 +157,10 @@ public class BukkitCompatibilityManager implements CompatibilityManager {
new MythicItemDropListener(this.plugin); new MythicItemDropListener(this.plugin);
logHook("MythicMobs"); 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")) { if (this.isPluginEnabled("QuickShop-Hikari")) {
new QuickShopItemExpressionHandler(this.plugin).register(); new QuickShopItemExpressionHandler(this.plugin).register();
logHook("QuickShop-Hikari"); logHook("QuickShop-Hikari");
} }
if (this.isPluginEnabled("CustomNameplates")) {
registerTagResolverProvider(new CustomNameplateProviders.Background());
registerTagResolverProvider(new CustomNameplateProviders.Nameplate());
registerTagResolverProvider(new CustomNameplateProviders.Bubble());
logHook("CustomNameplates");
}
} }
@Override @Override
@@ -233,7 +234,7 @@ public class BukkitCompatibilityManager implements CompatibilityManager {
Bukkit.getPluginManager().registerEvents(adaptor, plugin.javaPlugin()); Bukkit.getPluginManager().registerEvents(adaptor, plugin.javaPlugin());
logHook("AdvancedSlimePaper"); logHook("AdvancedSlimePaper");
} catch (ClassNotFoundException ignored) { } catch (ClassNotFoundException ignored) {
if (Bukkit.getPluginManager().isPluginEnabled("SlimeWorldPlugin")) { if (hasPlugin("SlimeWorldPlugin")) {
LegacySlimeFormatStorageAdaptor adaptor = new LegacySlimeFormatStorageAdaptor(worldManager, 2); LegacySlimeFormatStorageAdaptor adaptor = new LegacySlimeFormatStorageAdaptor(worldManager, 2);
worldManager.setStorageAdaptor(adaptor); worldManager.setStorageAdaptor(adaptor);
Bukkit.getPluginManager().registerEvents(adaptor, plugin.javaPlugin()); Bukkit.getPluginManager().registerEvents(adaptor, plugin.javaPlugin());

View File

@@ -2,11 +2,11 @@ package net.momirealms.craftengine.bukkit.compatibility.model.bettermodel;
import kr.toxicity.model.api.BetterModel; import kr.toxicity.model.api.BetterModel;
import kr.toxicity.model.api.data.renderer.ModelRenderer; 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; import org.bukkit.entity.Entity;
public class BetterModelUtils { public final class BetterModelUtils {
private BetterModelUtils() {}
public static void bindModel(Entity base, String id) { public static void bindModel(Entity base, String id) {
ModelRenderer renderer = BetterModel.plugin().modelManager().model(id); ModelRenderer renderer = BetterModel.plugin().modelManager().model(id);
@@ -15,8 +15,4 @@ public class BetterModelUtils {
} }
renderer.create(base); renderer.create(base);
} }
public static void registerConstantBlockEntityRender() {
BukkitBlockEntityElementConfigs.register(Key.of("craftengine:better_model"), new BetterModelBlockEntityElementConfig.Factory());
}
} }

View File

@@ -11,7 +11,6 @@ import net.momirealms.craftengine.core.world.World;
import org.bukkit.Location; import org.bukkit.Location;
import org.joml.Vector3f; import org.joml.Vector3f;
// TODO not tested yet
public class ModelEngineBlockEntityElement implements BlockEntityElement { public class ModelEngineBlockEntityElement implements BlockEntityElement {
private Dummy<?> dummy; private Dummy<?> dummy;
private final Location location; private final Location location;
@@ -41,14 +40,14 @@ public class ModelEngineBlockEntityElement implements BlockEntityElement {
@Override @Override
public void hide(Player player) { public void hide(Player player) {
if (this.dummy != null) { 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 @Override
public void show(Player player) { public void show(Player player) {
if (this.dummy != null) { if (this.dummy != null) {
this.dummy.setForceHidden((org.bukkit.entity.Player) player.platformPlayer(), true); this.dummy.setForceViewing((org.bukkit.entity.Player) player.platformPlayer(), true);
} }
} }

View File

@@ -3,11 +3,11 @@ package net.momirealms.craftengine.bukkit.compatibility.model.modelengine;
import com.ticxo.modelengine.api.ModelEngineAPI; import com.ticxo.modelengine.api.ModelEngineAPI;
import com.ticxo.modelengine.api.model.ActiveModel; import com.ticxo.modelengine.api.model.ActiveModel;
import com.ticxo.modelengine.api.model.ModeledEntity; 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; import org.bukkit.entity.Entity;
public class ModelEngineUtils { public final class ModelEngineUtils {
private ModelEngineUtils() {}
public static void bindModel(Entity base, String id) { public static void bindModel(Entity base, String id) {
ModeledEntity modeledEntity = ModelEngineAPI.createModeledEntity(base); ModeledEntity modeledEntity = ModelEngineAPI.createModeledEntity(base);
@@ -26,8 +26,4 @@ public class ModelEngineUtils {
} }
return entityId; return entityId;
} }
public static void registerConstantBlockEntityRender() {
BukkitBlockEntityElementConfigs.register(Key.of("craftengine:model_engine"), new ModelEngineBlockEntityElementConfig.Factory());
}
} }

View File

@@ -44,14 +44,14 @@ tasks.withType<JavaCompile> {
} }
bukkit { bukkit {
load = net.minecrell.pluginyml.bukkit.BukkitPluginDescription.PluginLoadOrder.POSTWORLD load = net.minecrell.pluginyml.bukkit.BukkitPluginDescription.PluginLoadOrder.STARTUP
main = "net.momirealms.craftengine.bukkit.plugin.BukkitCraftEnginePlugin" main = "net.momirealms.craftengine.bukkit.plugin.BukkitCraftEnginePlugin"
version = rootProject.properties["project_version"] as String version = rootProject.properties["project_version"] as String
name = "CraftEngine" name = "CraftEngine"
apiVersion = "1.20" apiVersion = "1.20"
authors = listOf("XiaoMoMi") authors = listOf("XiaoMoMi")
contributors = listOf("https://github.com/Xiao-MoMi/craft-engine/graphs/contributors") contributors = listOf("https://github.com/Xiao-MoMi/craft-engine/graphs/contributors")
softDepend = listOf("PlaceholderAPI", "WorldEdit", "FastAsyncWorldEdit", "Skript") softDepend = listOf("WorldEdit", "FastAsyncWorldEdit")
foliaSupported = true foliaSupported = true
} }
@@ -61,7 +61,7 @@ artifacts {
tasks { tasks {
shadowJar { 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")) destinationDirectory.set(file("$rootDir/target"))
relocate("net.kyori", "net.momirealms.craftengine.libraries") relocate("net.kyori", "net.momirealms.craftengine.libraries")
relocate("net.momirealms.sparrow.nbt", "net.momirealms.craftengine.libraries.nbt") relocate("net.momirealms.sparrow.nbt", "net.momirealms.craftengine.libraries.nbt")

View File

@@ -19,8 +19,6 @@ public class BukkitCraftEnginePlugin extends JavaPlugin {
@Override @Override
public void onEnable() { public void onEnable() {
this.plugin.onPluginEnable(); 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 @Override

View File

@@ -46,7 +46,7 @@ tasks.withType<JavaCompile> {
} }
paper { paper {
load = net.minecrell.pluginyml.bukkit.BukkitPluginDescription.PluginLoadOrder.POSTWORLD load = net.minecrell.pluginyml.bukkit.BukkitPluginDescription.PluginLoadOrder.STARTUP
main = "net.momirealms.craftengine.bukkit.plugin.PaperCraftEnginePlugin" main = "net.momirealms.craftengine.bukkit.plugin.PaperCraftEnginePlugin"
bootstrapper = "net.momirealms.craftengine.bukkit.plugin.PaperCraftEngineBootstrap" bootstrapper = "net.momirealms.craftengine.bukkit.plugin.PaperCraftEngineBootstrap"
version = rootProject.properties["project_version"] as String version = rootProject.properties["project_version"] as String
@@ -56,10 +56,7 @@ paper {
contributors = listOf("https://github.com/Xiao-MoMi/craft-engine/graphs/contributors") contributors = listOf("https://github.com/Xiao-MoMi/craft-engine/graphs/contributors")
foliaSupported = true foliaSupported = true
serverDependencies { serverDependencies {
register("PlaceholderAPI") { // WorldEdit
required = false
load = PaperPluginDescription.RelativeLoadOrder.BEFORE
}
register("WorldEdit") { register("WorldEdit") {
required = false required = false
load = PaperPluginDescription.RelativeLoadOrder.BEFORE load = PaperPluginDescription.RelativeLoadOrder.BEFORE
@@ -69,14 +66,18 @@ paper {
load = PaperPluginDescription.RelativeLoadOrder.BEFORE load = PaperPluginDescription.RelativeLoadOrder.BEFORE
joinClasspath = false joinClasspath = false
} }
register("Skript") {
required = false register("PlaceholderAPI") { required = false }
load = PaperPluginDescription.RelativeLoadOrder.BEFORE register("Skript") { required = false }
}
register("LuckPerms") { required = false } register("LuckPerms") { required = false }
register("ViaVersion") { required = false } register("ViaVersion") { required = false }
register("QuickShop-Hikari") { required = false } register("QuickShop-Hikari") { required = false }
// AdvancedSlimePaper
register("SlimeWorldPlugin") { required = false }
register("SlimeWorldManager") { required = false }
register("ASPaperPlugin") { required = false }
// external tag // external tag
register("CustomNameplates") { required = false } register("CustomNameplates") { required = false }
@@ -143,7 +144,7 @@ tasks {
manifest { manifest {
attributes["paperweight-mappings-namespace"] = "mojang" 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")) destinationDirectory.set(file("$rootDir/target"))
relocate("net.kyori", "net.momirealms.craftengine.libraries") relocate("net.kyori", "net.momirealms.craftengine.libraries")
relocate("net.momirealms.sparrow.nbt", "net.momirealms.craftengine.libraries.nbt") relocate("net.momirealms.sparrow.nbt", "net.momirealms.craftengine.libraries.nbt")

View File

@@ -18,8 +18,6 @@ public final class PaperCraftEnginePlugin extends JavaPlugin {
@Override @Override
public void onEnable() { public void onEnable() {
this.bootstrap.plugin.onPluginEnable(); 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 @Override

View File

@@ -1,9 +1,15 @@
package net.momirealms.craftengine.bukkit.block; 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.AbstractCustomBlock;
import net.momirealms.craftengine.core.block.BlockStateVariantProvider; import net.momirealms.craftengine.core.block.BlockStateVariantProvider;
import net.momirealms.craftengine.core.block.CustomBlock; 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.loot.LootTable;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.plugin.context.Context;
import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.plugin.context.event.EventTrigger;
import net.momirealms.craftengine.core.plugin.context.function.Function; 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.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
public final class BukkitCustomBlock extends AbstractCustomBlock { public final class BukkitCustomBlock extends AbstractCustomBlock {
@@ -24,4 +31,19 @@ public final class BukkitCustomBlock extends AbstractCustomBlock {
) { ) {
super(holder, variantProvider, events, lootTable); 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);
}
}
} }

View File

@@ -59,6 +59,15 @@ public class BukkitCustomBlockStateWrapper extends AbstractBlockStateWrapper imp
return this; 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 @Override
public boolean hasProperty(String propertyName) { public boolean hasProperty(String propertyName) {
return getImmutableBlockState().map(state -> state.owner().value().getProperty(propertyName) != null).orElse(false); return getImmutableBlockState().map(state -> state.owner().value().getProperty(propertyName) != null).orElse(false);
@@ -78,4 +87,9 @@ public class BukkitCustomBlockStateWrapper extends AbstractBlockStateWrapper imp
public Optional<ImmutableBlockState> getImmutableBlockState() { public Optional<ImmutableBlockState> getImmutableBlockState() {
return BlockStateUtils.getOptionalCustomBlockState(super.blockState); return BlockStateUtils.getOptionalCustomBlockState(super.blockState);
} }
@Override
public boolean isAir() {
return false;
}
} }

View File

@@ -54,4 +54,16 @@ public class BukkitVanillaBlockStateWrapper extends AbstractBlockStateWrapper {
if (newState == super.blockState) return this; if (newState == super.blockState) return this;
return BlockRegistryMirror.byId(BlockStateUtils.blockStateToId(newState)); 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);
}
} }

View File

@@ -7,7 +7,7 @@ import net.momirealms.craftengine.bukkit.util.LocationUtils;
import net.momirealms.craftengine.core.block.BlockBehavior; import net.momirealms.craftengine.core.block.BlockBehavior;
import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; 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.plugin.CraftEngine;
import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.util.VersionHelper;

View File

@@ -44,6 +44,8 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
public static final Key CHIME_BLOCK = Key.from("craftengine:chime_block"); 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 BUDDING_BLOCK = Key.from("craftengine:budding_block");
public static final Key SEAT_BLOCK = Key.from("craftengine:seat_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() { public static void init() {
register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE); register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE);
@@ -86,5 +88,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
register(CHIME_BLOCK, ChimeBlockBehavior.FACTORY); register(CHIME_BLOCK, ChimeBlockBehavior.FACTORY);
register(BUDDING_BLOCK, BuddingBlockBehavior.FACTORY); register(BUDDING_BLOCK, BuddingBlockBehavior.FACTORY);
register(SEAT_BLOCK, SeatBlockBehavior.FACTORY); register(SEAT_BLOCK, SeatBlockBehavior.FACTORY);
register(SURFACE_SPREADING_BLOCK, SurfaceSpreadingBlockBehavior.FACTORY);
register(SNOWY_BLOCK, SnowyBlockBehavior.FACTORY);
} }
} }

View File

@@ -169,9 +169,24 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior {
} }
@Override @Override
public void setPlacedBy(BlockPlaceContext context, ImmutableBlockState state) { public boolean canPlaceMultiState(BlockAccessor accessor, BlockPos pos, ImmutableBlockState state) {
BlockPos pos = context.getClickedPos(); if (pos.y() >= accessor.worldHeight().getMaxBuildHeight() - 1) {
context.getLevel().setBlockAt(pos.x(), pos.y() + 1, pos.z(), state.with(this.halfProperty, DoubleBlockHalf.UPPER).customBlockState(), UpdateOption.UPDATE_ALL.flags()); return false;
}
return accessor.getBlockState(pos.above()).isAir();
}
@Override
public void placeMultiState(Object thisBlock, Object[] args, Callable<Object> superMethod) {
Object blockState = args[2];
Object pos = args[1];
Optional<ImmutableBlockState> 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 @Override
@@ -179,7 +194,7 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior {
World world = context.getLevel(); World world = context.getLevel();
Object level = world.serverWorld(); Object level = world.serverWorld();
BlockPos pos = context.getClickedPos(); 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())); 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) return state.with(this.poweredProperty, hasSignal)
.with(this.facingProperty, context.getHorizontalDirection().toHorizontalDirection()) .with(this.facingProperty, context.getHorizontalDirection().toHorizontalDirection())

View File

@@ -1,31 +1,38 @@
package net.momirealms.craftengine.bukkit.block.behavior; 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.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; 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.MBlocks;
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
import net.momirealms.craftengine.bukkit.util.BlockStateUtils; 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.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.behavior.BlockBehaviorFactory;
import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.block.properties.type.DoubleBlockHalf; 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.item.context.BlockPlaceContext;
import net.momirealms.craftengine.core.util.Direction;
import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.*;
import net.momirealms.craftengine.core.world.World; import org.bukkit.inventory.ItemStack;
import net.momirealms.craftengine.core.world.WorldEvents;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
public class DoubleHighBlockBehavior extends BukkitBlockBehavior { public class DoubleHighBlockBehavior extends AbstractCanSurviveBlockBehavior {
public static final Factory FACTORY = new Factory(); public static final Factory FACTORY = new Factory();
private final Property<DoubleBlockHalf> halfProperty; private final Property<DoubleBlockHalf> halfProperty;
public DoubleHighBlockBehavior(CustomBlock customBlock, Property<DoubleBlockHalf> halfProperty) { public DoubleHighBlockBehavior(CustomBlock customBlock, Property<DoubleBlockHalf> halfProperty) {
super(customBlock); super(customBlock, 0);
this.halfProperty = halfProperty; this.halfProperty = halfProperty;
} }
@@ -34,40 +41,100 @@ public class DoubleHighBlockBehavior extends BukkitBlockBehavior {
Object level = args[updateShape$level]; Object level = args[updateShape$level];
Object blockPos = args[updateShape$blockPos]; Object blockPos = args[updateShape$blockPos];
Object blockState = args[0]; Object blockState = args[0];
ImmutableBlockState customState = BlockStateUtils.getOptionalCustomBlockState(blockState).orElse(null);
ImmutableBlockState customState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
if (customState == null || customState.isEmpty()) return blockState; if (customState == null || customState.isEmpty()) return blockState;
DoubleBlockHalf half = customState.get(this.halfProperty); DoubleBlockHalf half = customState.get(this.halfProperty);
if (half == null) return blockState; 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);
Object anotherHalfPos = FastNMS.INSTANCE.method$BlockPos$relative(blockPos, if (neighborState == null || neighborState.isEmpty()) return MBlocks.AIR$defaultState;
half == DoubleBlockHalf.UPPER DoubleHighBlockBehavior anotherDoorBehavior = neighborState.behavior().getAs(DoubleHighBlockBehavior.class).orElse(null);
? CoreReflections.instance$Direction$DOWN if (anotherDoorBehavior == null) return MBlocks.AIR$defaultState;
: CoreReflections.instance$Direction$UP if (neighborState.get(anotherDoorBehavior.halfProperty) != half) {
); return neighborState.with(anotherDoorBehavior.halfProperty, half).customBlockState().literalObject();
Object anotherHalfState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, anotherHalfPos); }
ImmutableBlockState anotherHalfCustomState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(anotherHalfState)); return MBlocks.AIR$defaultState;
if (anotherHalfCustomState != null && !anotherHalfCustomState.isEmpty()) return blockState; } 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));
FastNMS.INSTANCE.method$LevelAccessor$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId()); WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(pos));
return MBlocks.AIR$defaultState; 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 @Override
public void setPlacedBy(BlockPlaceContext context, ImmutableBlockState state) { public Object playerWillDestroy(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
World level = context.getLevel(); Object level = args[0];
BlockPos anotherHalfPos = context.getClickedPos().relative(Direction.UP); Object pos = args[1];
BlockStateWrapper blockStateWrapper = state.with(this.halfProperty, DoubleBlockHalf.UPPER).customBlockState(); Object state = args[2];
FastNMS.INSTANCE.method$LevelWriter$setBlock(level.serverWorld(), LocationUtils.toBlockPos(anotherHalfPos), blockStateWrapper.literalObject(), UpdateOption.Flags.UPDATE_CLIENTS); 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<ItemStack> 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<DoubleHighBlockBehavior> 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<ImmutableBlockState> 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<Object> superMethod) {
Object blockState = args[2];
Object pos = args[1];
Optional<ImmutableBlockState> 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 @Override
public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) { public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) {
World world = context.getLevel(); World world = context.getLevel();
BlockPos pos = context.getClickedPos(); 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 state.with(this.halfProperty, DoubleBlockHalf.LOWER);
} }
return null; return null;

View File

@@ -96,10 +96,10 @@ public class FenceBlockBehavior extends BukkitBlockBehavior {
BlockPos blockPos1 = clickedPos.east(); BlockPos blockPos1 = clickedPos.east();
BlockPos blockPos2 = clickedPos.south(); BlockPos blockPos2 = clickedPos.south();
BlockPos blockPos3 = clickedPos.west(); BlockPos blockPos3 = clickedPos.west();
BlockStateWrapper blockState = level.getBlockAt(blockPos).blockState(); BlockStateWrapper blockState = level.getBlock(blockPos).blockState();
BlockStateWrapper blockState1 = level.getBlockAt(blockPos1).blockState(); BlockStateWrapper blockState1 = level.getBlock(blockPos1).blockState();
BlockStateWrapper blockState2 = level.getBlockAt(blockPos2).blockState(); BlockStateWrapper blockState2 = level.getBlock(blockPos2).blockState();
BlockStateWrapper blockState3 = level.getBlockAt(blockPos3).blockState(); BlockStateWrapper blockState3 = level.getBlock(blockPos3).blockState();
BooleanProperty waterlogged = (BooleanProperty) state.owner().value().getProperty("waterlogged"); BooleanProperty waterlogged = (BooleanProperty) state.owner().value().getProperty("waterlogged");
if (waterlogged != null) { if (waterlogged != null) {
state = state.with(waterlogged, FastNMS.INSTANCE.method$FluidState$getType(fluidState) == MFluids.WATER); state = state.with(waterlogged, FastNMS.INSTANCE.method$FluidState$getType(fluidState) == MFluids.WATER);

View File

@@ -86,7 +86,7 @@ public class GrassBlockBehavior extends BukkitBlockBehavior {
if (ItemUtils.isEmpty(item) || !item.vanillaId().equals(ItemKeys.BONE_MEAL) || context.getPlayer().isAdventureMode()) if (ItemUtils.isEmpty(item) || !item.vanillaId().equals(ItemKeys.BONE_MEAL) || context.getPlayer().isAdventureMode())
return InteractionResult.PASS; return InteractionResult.PASS;
BlockPos pos = context.getClickedPos(); 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(); Block block = upper.block();
if (!block.isEmpty()) if (!block.isEmpty())
return InteractionResult.PASS; return InteractionResult.PASS;

View File

@@ -6,7 +6,7 @@ import net.momirealms.craftengine.core.block.BlockBehavior;
import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.UpdateOption; import net.momirealms.craftengine.core.block.UpdateOption;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; 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 net.momirealms.craftengine.core.world.WorldEvents;
import java.util.Map; import java.util.Map;

View File

@@ -60,7 +60,7 @@ public class SlabBlockBehavior extends BukkitBlockBehavior {
@Override @Override
public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) { public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) {
BlockPos clickedPos = context.getClickedPos(); 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 (blockState != null && blockState.owner().value() == super.customBlock) {
if (super.waterloggedProperty != null) if (super.waterloggedProperty != null)
blockState = blockState.with(super.waterloggedProperty, false); blockState = blockState.with(super.waterloggedProperty, false);

View File

@@ -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<Object> 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<String, Object> arguments) {
BooleanProperty snowyProperty = (BooleanProperty) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("snowy"), "warning.config.block.behavior.snowy.missing_snowy");
return new SnowyBlockBehavior(block, snowyProperty);
}
}
}

View File

@@ -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<Object> baseBlock;
private final Property<Boolean> snowyProperty;
public SurfaceSpreadingBlockBehavior(CustomBlock customBlock, int requiredLight, String baseBlock, @Nullable Property<Boolean> 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<Object> 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<String, Object> 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<Boolean>) block.getProperty("snowy"));
}
}
}

View File

@@ -4,11 +4,13 @@ import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior; import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior;
import net.momirealms.craftengine.core.block.behavior.EntityBlockBehavior; import net.momirealms.craftengine.core.block.behavior.EntityBlockBehavior;
import net.momirealms.craftengine.core.block.behavior.special.FallOnBlockBehavior; import net.momirealms.craftengine.core.block.behavior.FallOnBlockBehavior;
import net.momirealms.craftengine.core.block.behavior.special.PlaceLiquidBlockBehavior; import net.momirealms.craftengine.core.block.behavior.PlaceLiquidBlockBehavior;
import net.momirealms.craftengine.core.entity.player.InteractionResult; import net.momirealms.craftengine.core.entity.player.InteractionResult;
import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
import net.momirealms.craftengine.core.item.context.UseOnContext; 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 org.jetbrains.annotations.Nullable;
import java.util.List; import java.util.List;
@@ -119,7 +121,6 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior
return previous; return previous;
} }
@Override @Override
public Object getContainer(Object thisBlock, Object[] args) throws Exception { public Object getContainer(Object thisBlock, Object[] args) throws Exception {
for (AbstractBlockBehavior behavior : this.behaviors) { 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 @Override
public boolean canBeReplaced(BlockPlaceContext context, ImmutableBlockState state) { public boolean canBeReplaced(BlockPlaceContext context, ImmutableBlockState state) {
for (AbstractBlockBehavior behavior : this.behaviors) { for (AbstractBlockBehavior behavior : this.behaviors) {
@@ -399,4 +393,31 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior
behavior.onProjectileHit(thisBlock, args, superMethod); behavior.onProjectileHit(thisBlock, args, superMethod);
} }
} }
@Override
public void placeMultiState(Object thisBlock, Object[] args, Callable<Object> 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;
}
} }

View File

@@ -175,7 +175,7 @@ public class SimpleStorageBlockEntity extends BlockEntity {
if (state == null || state.behavior() != this.behavior) return; if (state == null || state.behavior() != this.behavior) return;
Property<Boolean> property = this.behavior.openProperty(); Property<Boolean> property = this.behavior.openProperty();
if (property == null) return; 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) { public void checkOpeners(Object level, Object pos, Object blockState) {

View File

@@ -75,7 +75,6 @@ public class BukkitFurniture implements Furniture {
this.hasExternalModel = false; this.hasExternalModel = false;
} }
Quaternionf conjugated = QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - this.location.getYaw()), 0).conjugate(); Quaternionf conjugated = QuaternionUtils.toQuaternionf(0, Math.toRadians(180 - this.location.getYaw()), 0).conjugate();
List<Object> packets = new ArrayList<>(); List<Object> packets = new ArrayList<>();
List<Object> minimizedPackets = new ArrayList<>(); List<Object> minimizedPackets = new ArrayList<>();

View File

@@ -77,7 +77,7 @@ public class AxeItemBehavior extends ItemBehavior {
} }
newState = newState.withProperties(behaviorOptional.get().filter(customState.propertiesNbt())); 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; org.bukkit.entity.Player bukkitPlayer = null;
if (player != null) { if (player != null) {
bukkitPlayer = ((org.bukkit.entity.Player) player.platformPlayer()); bukkitPlayer = ((org.bukkit.entity.Player) player.platformPlayer());

View File

@@ -81,7 +81,7 @@ public class BlockItemBehavior extends BlockBoundItemBehavior {
CustomBlock block = optionalBlock.get(); CustomBlock block = optionalBlock.get();
BlockPos pos = context.getClickedPos(); BlockPos pos = context.getClickedPos();
int maxY = context.getLevel().worldHeight().getMaxBuildHeight() - 1; 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) { if (player != null) {
player.sendActionBar(Component.translatable("build.tooHigh").arguments(Component.text(maxY)).color(NamedTextColor.RED)); player.sendActionBar(Component.translatable("build.tooHigh").arguments(Component.text(maxY)).color(NamedTextColor.RED));
} }

View File

@@ -38,7 +38,7 @@ public class CompostableItemBehavior extends ItemBehavior {
@SuppressWarnings("UnstableApiUsage") @SuppressWarnings("UnstableApiUsage")
@Override @Override
public InteractionResult useOnBlock(UseOnContext context) { 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(); BlockData blockData = block.block().getBlockData();
Object blockOwner = BlockStateUtils.getBlockOwner(BlockStateUtils.blockDataToBlockState(blockData)); Object blockOwner = BlockStateUtils.getBlockOwner(BlockStateUtils.blockDataToBlockState(blockData));
if (blockOwner != MBlocks.COMPOSTER) return InteractionResult.PASS; if (blockOwner != MBlocks.COMPOSTER) return InteractionResult.PASS;

View File

@@ -40,7 +40,7 @@ public class FlintAndSteelItemBehavior extends ItemBehavior {
if (player == null) return InteractionResult.PASS; if (player == null) return InteractionResult.PASS;
BlockPos clickedPos = context.getClickedPos(); BlockPos clickedPos = context.getClickedPos();
BukkitExistingBlock clicked = (BukkitExistingBlock) context.getLevel().getBlockAt(clickedPos); BukkitExistingBlock clicked = (BukkitExistingBlock) context.getLevel().getBlock(clickedPos);
Block block = clicked.block(); Block block = clicked.block();
BlockPos firePos = clickedPos.relative(context.getClickedFace()); BlockPos firePos = clickedPos.relative(context.getClickedFace());
Direction direction = context.getHorizontalDirection(); Direction direction = context.getHorizontalDirection();
@@ -95,7 +95,7 @@ public class FlintAndSteelItemBehavior extends ItemBehavior {
} else { } else {
// 玩家觉得自定义方块不可燃,且点击了侧面,那么就要判断火源下方的方块是否可燃,如果不可燃,则补发声音 // 玩家觉得自定义方块不可燃,且点击了侧面,那么就要判断火源下方的方块是否可燃,如果不可燃,则补发声音
BlockPos belowFirePos = firePos.relative(Direction.DOWN); BlockPos belowFirePos = firePos.relative(Direction.DOWN);
BukkitExistingBlock belowFireBlock = (BukkitExistingBlock) context.getLevel().getBlockAt(belowFirePos); BukkitExistingBlock belowFireBlock = (BukkitExistingBlock) context.getLevel().getBlock(belowFirePos);
boolean belowCanBurn; boolean belowCanBurn;
try { try {
Block belowBlock = belowFireBlock.block(); Block belowBlock = belowFireBlock.block();
@@ -134,7 +134,7 @@ public class FlintAndSteelItemBehavior extends ItemBehavior {
for (Direction dir : Direction.values()) { for (Direction dir : Direction.values()) {
if (dir == relativeDirection) continue; if (dir == relativeDirection) continue;
BlockPos relPos = firePos.relative(dir); BlockPos relPos = firePos.relative(dir);
BukkitExistingBlock nearByBlock = (BukkitExistingBlock) context.getLevel().getBlockAt(relPos); BukkitExistingBlock nearByBlock = (BukkitExistingBlock) context.getLevel().getBlock(relPos);
BlockData nearbyBlockData = nearByBlock.block().getBlockData(); BlockData nearbyBlockData = nearByBlock.block().getBlockData();
Object nearbyBlockState = BlockStateUtils.blockDataToBlockState(nearbyBlockData); Object nearbyBlockState = BlockStateUtils.blockDataToBlockState(nearbyBlockData);
int stateID = BlockStateUtils.blockStateToId(nearbyBlockState); int stateID = BlockStateUtils.blockStateToId(nearbyBlockState);

View File

@@ -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.behavior.ItemBehaviorFactory;
import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.item.context.UseOnContext;
import net.momirealms.craftengine.core.pack.Pack; 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.CraftEngine;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.Direction;

View File

@@ -449,6 +449,30 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory<ComponentItemW
} }
} }
@Override
protected Optional<List<Enchantment>> 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<List<Enchantment>> 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 @Override
protected void storedEnchantments(ComponentItemWrapper item, List<Enchantment> enchantments) { protected void storedEnchantments(ComponentItemWrapper item, List<Enchantment> enchantments) {
if (enchantments == null || enchantments.isEmpty()) { if (enchantments == null || enchantments.isEmpty()) {

View File

@@ -226,6 +226,34 @@ public class UniversalItemFactory extends BukkitItemFactory<LegacyItemWrapper> {
return Optional.of(new Enchantment(key, level)); return Optional.of(new Enchantment(key, level));
} }
@SuppressWarnings("DuplicatedCode")
@Override
protected Optional<List<Enchantment>> enchantments(LegacyItemWrapper item) {
ListTag enchantmentTag = (ListTag) item.getNBTTag("Enchantments");
if (enchantmentTag == null) return Optional.empty();
List<Enchantment> 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<List<Enchantment>> storedEnchantments(LegacyItemWrapper item) {
ListTag enchantmentTag = (ListTag) item.getNBTTag("StoredEnchantments");
if (enchantmentTag == null) return Optional.empty();
List<Enchantment> 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 @Override
protected void itemFlags(LegacyItemWrapper item, List<String> flags) { protected void itemFlags(LegacyItemWrapper item, List<String> flags) {
if (flags == null || flags.isEmpty()) { if (flags == null || flags.isEmpty()) {

View File

@@ -56,6 +56,7 @@ public class BukkitPackManager extends AbstractPackManager implements Listener {
public void onPlayerJoin(PlayerJoinEvent event) { public void onPlayerJoin(PlayerJoinEvent event) {
if (Config.sendPackOnJoin() && !VersionHelper.isOrAbove1_20_2()) { if (Config.sendPackOnJoin() && !VersionHelper.isOrAbove1_20_2()) {
Player player = BukkitAdaptors.adapt(event.getPlayer()); Player player = BukkitAdaptors.adapt(event.getPlayer());
// 可能有假人
if (player == null) return; if (player == null) return;
this.sendResourcePack(player); this.sendResourcePack(player);
} }

View File

@@ -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.config.Config;
import net.momirealms.craftengine.core.plugin.dependency.Dependencies; import net.momirealms.craftengine.core.plugin.dependency.Dependencies;
import net.momirealms.craftengine.core.plugin.dependency.Dependency; 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.JavaPluginLogger;
import net.momirealms.craftengine.core.plugin.logger.PluginLogger; import net.momirealms.craftengine.core.plugin.logger.PluginLogger;
import net.momirealms.craftengine.core.plugin.scheduler.SchedulerAdapter; import net.momirealms.craftengine.core.plugin.scheduler.SchedulerAdapter;
@@ -56,7 +54,6 @@ import org.jspecify.annotations.Nullable;
import java.io.*; import java.io.*;
import java.net.URL; import java.net.URL;
import java.net.URLConnection; import java.net.URLConnection;
import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@@ -104,17 +101,13 @@ public class BukkitCraftEngine extends CraftEngine {
this.javaPlugin = javaPlugin; this.javaPlugin = javaPlugin;
} }
protected void setUpConfigAndLocale() { @Override
this.config = new Config(this); public void setUpConfigAndLocale() {
this.config.updateConfigCache(); super.setUpConfigAndLocale();
// 先读取语言后,再重载语言文件系统 super.packManager = new BukkitPackManager(this);
this.config.loadForcedLocale();
this.translationManager = new TranslationManagerImpl(this);
this.translationManager.reload();
// 最后才加载完整的config配置
this.config.loadFullSettings();
} }
// 这个方法应该尽早被执行最好是boostrap阶段
public void injectRegistries() { public void injectRegistries() {
if (super.blockManager != null) return; if (super.blockManager != null) return;
try { try {
@@ -129,13 +122,25 @@ public class BukkitCraftEngine extends CraftEngine {
} catch (Exception e) { } catch (Exception e) {
throw new InjectionException("Error injecting loot entries", 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 @Override
public void onPluginLoad() { public void onPluginLoad() {
// 普通bukkit插件会到这里才注册自定义方块
if (super.blockManager == null) { if (super.blockManager == null) {
this.injectRegistries(); this.injectRegistries();
} }
// 注入一些新的类型,但是并不需要太早
try { try {
WorldStorageInjector.init(); WorldStorageInjector.init();
} catch (Exception e) { } catch (Exception e) {
@@ -151,12 +156,44 @@ public class BukkitCraftEngine extends CraftEngine {
} catch (Exception e) { } catch (Exception e) {
throw new InjectionException("Error initializing ProtectedFieldVisitor", e); throw new InjectionException("Error initializing ProtectedFieldVisitor", e);
} }
// 初始化一些注册表
super.onPluginLoad(); super.onPluginLoad();
super.networkManager = new BukkitNetworkManager(this); BukkitBlockBehaviors.init();
super.blockManager.init(); BukkitItemBehaviors.init();
super.itemManager = new BukkitItemManager(this); BukkitHitBoxTypes.init();
this.successfullyLoaded = true; BukkitBlockEntityElementConfigs.init();
// 初始化 onload 阶段的兼容性
super.compatibilityManager().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 @Override
@@ -193,39 +230,16 @@ public class BukkitCraftEngine extends CraftEngine {
Bukkit.getServer().shutdown(); Bukkit.getServer().shutdown();
return; return;
} }
BukkitBlockBehaviors.init(); // 初始化指令发送者工厂
BukkitItemBehaviors.init();
BukkitHitBoxTypes.init();
BukkitBlockEntityElementConfigs.init();
super.packManager = new BukkitPackManager(this);
super.senderFactory = new BukkitSenderFactory(this); super.senderFactory = new BukkitSenderFactory(this);
super.recipeManager = new BukkitRecipeManager(this); // 初始化指令管理器
super.commandManager = new BukkitCommandManager(this); super.commandManager = new BukkitCommandManager(this);
super.itemBrowserManager = new ItemBrowserManagerImpl(this); try {
super.guiManager = new BukkitGuiManager(this); super.compatibilityManager().onEnable();
super.worldManager = new BukkitWorldManager(this); } catch (Throwable t) {
super.soundManager = new BukkitSoundManager(this); this.logger.severe("Failed to enable compatibility manager", t);
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);
}
} }
super.onPluginEnable();
} }
@Override @Override

View File

@@ -25,7 +25,7 @@ import net.momirealms.craftengine.core.block.BlockKeys;
import net.momirealms.craftengine.core.block.BlockShape; import net.momirealms.craftengine.core.block.BlockShape;
import net.momirealms.craftengine.core.block.DelegatingBlock; import net.momirealms.craftengine.core.block.DelegatingBlock;
import net.momirealms.craftengine.core.block.behavior.EmptyBlockBehavior; 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.CraftEngine;
import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Key;
@@ -175,6 +175,9 @@ public final class BlockGenerator {
// onProjectileHit // onProjectileHit
.method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$onProjectileHit)) .method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$onProjectileHit))
.intercept(MethodDelegation.to(OnProjectileHitInterceptor.INSTANCE)) .intercept(MethodDelegation.to(OnProjectileHitInterceptor.INSTANCE))
// setPlaceBy
.method(ElementMatchers.is(CoreReflections.method$Block$setPlacedBy))
.intercept(MethodDelegation.to(SetPlaceByInterceptor.INSTANCE))
; ;
// 1.21.5+ // 1.21.5+
if (CoreReflections.method$BlockBehaviour$affectNeighborsAfterRemoval != null) { 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<Object> superMethod) {
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
try {
holder.value().placeMultiState(thisObj, args, superMethod);
} catch (Exception e) {
CraftEngine.instance().logger().severe("Failed to run setPlaceBy", e);
}
}
}
} }

View File

@@ -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());
}
}

View File

@@ -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);
}
}

View File

@@ -18,6 +18,8 @@ import java.lang.reflect.Modifier;
public final class ProtectedFieldVisitor { public final class ProtectedFieldVisitor {
private static FieldAccessor internalFieldAccessor; private static FieldAccessor internalFieldAccessor;
private ProtectedFieldVisitor() {}
public static void init() throws ReflectiveOperationException { public static void init() throws ReflectiveOperationException {
ByteBuddy byteBuddy = new ByteBuddy(ClassFileVersion.JAVA_V17); ByteBuddy byteBuddy = new ByteBuddy(ClassFileVersion.JAVA_V17);
// InternalFieldAccessor Interface // InternalFieldAccessor Interface

View File

@@ -40,6 +40,8 @@ public final class RecipeInjector {
private static Class<?> clazz$InjectedRepairItemRecipe; private static Class<?> clazz$InjectedRepairItemRecipe;
private static Class<?> clazz$InjectedFireworkStarFadeRecipe; private static Class<?> clazz$InjectedFireworkStarFadeRecipe;
private RecipeInjector() {}
public static void init() { public static void init() {
ByteBuddy byteBuddy = new ByteBuddy(ClassFileVersion.JAVA_V17); ByteBuddy byteBuddy = new ByteBuddy(ClassFileVersion.JAVA_V17);

View File

@@ -43,6 +43,8 @@ public final class WorldStorageInjector {
private static Class<?> clazz$InjectedPalettedContainer; private static Class<?> clazz$InjectedPalettedContainer;
private static MethodHandle constructor$InjectedLevelChunkSection; private static MethodHandle constructor$InjectedLevelChunkSection;
private WorldStorageInjector() {}
public static void init() throws ReflectiveOperationException { public static void init() throws ReflectiveOperationException {
ByteBuddy byteBuddy = new ByteBuddy(ClassFileVersion.JAVA_V17); ByteBuddy byteBuddy = new ByteBuddy(ClassFileVersion.JAVA_V17);
// Paletted Container // Paletted Container

View File

@@ -121,6 +121,7 @@ import org.jetbrains.annotations.Nullable;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiFunction; import java.util.function.BiFunction;
@@ -433,6 +434,11 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
new SetObjectiveListener1_20(), new SetObjectiveListener1_20(),
this.packetIds.clientboundSetObjectivePacket(), "ClientboundSetObjectivePacket" 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) @EventHandler(priority = EventPriority.LOWEST)
@@ -1118,7 +1124,6 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
@Override @Override
public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) {
BukkitServerPlayer player = (BukkitServerPlayer) user; BukkitServerPlayer player = (BukkitServerPlayer) user;
if (!player.isMiningBlock()) return;
Object hand = FastNMS.INSTANCE.field$ServerboundSwingPacket$hand(packet); Object hand = FastNMS.INSTANCE.field$ServerboundSwingPacket$hand(packet);
if (hand == CoreReflections.instance$InteractionHand$MAIN_HAND) { if (hand == CoreReflections.instance$InteractionHand$MAIN_HAND) {
player.onSwingHand(); 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<Pair<Integer, byte[]>> 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<String, ComponentProvider> 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<String, ComponentProvider> 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<String, ComponentProvider> 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<Pair<Integer, byte[]>> 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<String, ComponentProvider> 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<String, ComponentProvider> 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<String, ComponentProvider> 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));
}
}
}
} }

View File

@@ -75,4 +75,6 @@ public interface PacketIds {
int clientboundForgetLevelChunkPacket(); int clientboundForgetLevelChunkPacket();
int serverboundCustomPayloadPacket(); int serverboundCustomPayloadPacket();
int clientboundPlayerChatPacket();
} }

View File

@@ -190,4 +190,9 @@ public class PacketIds1_20 implements PacketIds {
public int serverboundCustomPayloadPacket() { public int serverboundCustomPayloadPacket() {
return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ServerboundCustomPayloadPacket, PacketFlow.SERVERBOUND); return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ServerboundCustomPayloadPacket, PacketFlow.SERVERBOUND);
} }
@Override
public int clientboundPlayerChatPacket() {
return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundPlayerChatPacket, PacketFlow.CLIENTBOUND);
}
} }

View File

@@ -189,4 +189,9 @@ public class PacketIds1_20_5 implements PacketIds {
public int serverboundCustomPayloadPacket() { public int serverboundCustomPayloadPacket() {
return PlayPacketIdHelper.byName("minecraft:custom_payload", PacketFlow.SERVERBOUND); return PlayPacketIdHelper.byName("minecraft:custom_payload", PacketFlow.SERVERBOUND);
} }
@Override
public int clientboundPlayerChatPacket() {
return PlayPacketIdHelper.byName("minecraft:player_chat", PacketFlow.CLIENTBOUND);
}
} }

View File

@@ -639,7 +639,6 @@ public final class CoreReflections {
), VersionHelper.isOrAbove1_21_5()); ), VersionHelper.isOrAbove1_21_5());
public static final Method method$Registry$getId = requireNonNull( public static final Method method$Registry$getId = requireNonNull(
ReflectionUtils.getMethod(clazz$Registry, int.class, Object.class) 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) 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( public static final Class<?> clazz$ItemCost = MiscUtils.requireNonNullIf(
BukkitReflectionUtils.findReobfOrMojmapClass( BukkitReflectionUtils.findReobfOrMojmapClass(
"world.item.trading.ItemCost", "world.item.trading.ItemCost",
@@ -4548,4 +4551,25 @@ public final class CoreReflections {
public static final Field field$ChunkMap$chunkGenerator = MiscUtils.requireNonNullIf( public static final Field field$ChunkMap$chunkGenerator = MiscUtils.requireNonNullIf(
ReflectionUtils.getDeclaredField(clazz$ChunkMap, clazz$ChunkGenerator, 0), !VersionHelper.isOrAbove1_20_5() 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"
)
);
} }

View File

@@ -26,6 +26,8 @@ public final class MBuiltInRegistries {
public static final Object DATA_COMPONENT_PREDICATE_TYPE; public static final Object DATA_COMPONENT_PREDICATE_TYPE;
public static final Object LOOT_POOL_ENTRY_TYPE; public static final Object LOOT_POOL_ENTRY_TYPE;
public static final Object GAME_EVENT; public static final Object GAME_EVENT;
public static final Object BLOCKSTATE_PROVIDER_TYPE;
public static final Object FEATURE;
static { static {
Field[] fields = CoreReflections.clazz$BuiltInRegistries.getDeclaredFields(); Field[] fields = CoreReflections.clazz$BuiltInRegistries.getDeclaredFields();
@@ -44,6 +46,8 @@ public final class MBuiltInRegistries {
Object registries$DataComponentPredicateType = null; Object registries$DataComponentPredicateType = null;
Object registries$LootPoolEntryType = null; Object registries$LootPoolEntryType = null;
Object registries$GameEvent = null; Object registries$GameEvent = null;
Object registries$BlockStateProviderType = null;
Object registries$Feature = null;
for (Field field : fields) { for (Field field : fields) {
Type fieldType = field.getGenericType(); Type fieldType = field.getGenericType();
@@ -59,6 +63,10 @@ public final class MBuiltInRegistries {
registries$RecipeType = field.get(null); registries$RecipeType = field.get(null);
} else if (rawType == CoreReflections.clazz$BlockEntityType) { } else if (rawType == CoreReflections.clazz$BlockEntityType) {
registries$BlockEntityType = field.get(null); 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) { } else if (VersionHelper.isOrAbove1_20_5() && rawType == CoreReflections.clazz$DataComponentType && registries$DataComponentType == null) {
registries$DataComponentType = field.get(null); registries$DataComponentType = field.get(null);
} else if (VersionHelper.isOrAbove1_21_5() && rawType == CoreReflections.clazz$DataComponentPredicate$Type) { } 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); LOOT_POOL_ENTRY_TYPE = requireNonNull(registries$LootPoolEntryType);
DATA_COMPONENT_TYPE = registries$DataComponentType; DATA_COMPONENT_TYPE = registries$DataComponentType;
GAME_EVENT = requireNonNull(registries$GameEvent); GAME_EVENT = requireNonNull(registries$GameEvent);
BLOCKSTATE_PROVIDER_TYPE = requireNonNull(registries$BlockStateProviderType);
FEATURE = requireNonNull(registries$Feature);
DATA_COMPONENT_PREDICATE_TYPE = registries$DataComponentPredicateType; DATA_COMPONENT_PREDICATE_TYPE = registries$DataComponentPredicateType;
} catch (ReflectiveOperationException e) { } catch (ReflectiveOperationException e) {
throw new ReflectionInitException("Failed to init BuiltInRegistries", e); throw new ReflectionInitException("Failed to init BuiltInRegistries", e);

View File

@@ -7,12 +7,14 @@ import java.util.Objects;
public final class MTagKeys { public final class MTagKeys {
private 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 Item$WOOL = create(MRegistries.ITEM, "wool");
public static final Object Block$WALLS = create(MRegistries.BLOCK, "walls"); 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$SHULKER_BOXES = create(MRegistries.BLOCK, "shulker_boxes");
public static final Object Block$FENCES = create(MRegistries.BLOCK, "fences"); 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$WOODEN_FENCES = create(MRegistries.BLOCK, "wooden_fences");
public static final Object Block$DIRT = create(MRegistries.BLOCK, "dirt"); 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) { private static Object create(Object registry, String location) {
Object resourceLocation = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", location); Object resourceLocation = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", location);

View File

@@ -1726,4 +1726,10 @@ public final class NetworkReflections {
clazz$ClientboundUpdateTagsPacket, Map.class, 0 clazz$ClientboundUpdateTagsPacket, Map.class, 0
) )
); );
public static final Class<?> clazz$ClientboundPlayerChatPacket = requireNonNull(
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("network.protocol.game.ClientboundPlayerChatPacket")
)
);
} }

View File

@@ -104,6 +104,7 @@ public class BukkitServerPlayer extends Player {
private boolean isDestroyingBlock; private boolean isDestroyingBlock;
private boolean isDestroyingCustomBlock; private boolean isDestroyingCustomBlock;
private boolean swingHandAck; private boolean swingHandAck;
private int lastSwingHandTick;
private float miningProgress; private float miningProgress;
// for client visual sync // for client visual sync
private int resentSoundTick; private int resentSoundTick;
@@ -131,6 +132,12 @@ public class BukkitServerPlayer extends Player {
// selected client locale // selected client locale
@Nullable @Nullable
private Locale selectedLocale; private Locale selectedLocale;
// 存储客户端在发送停止破坏包前正在破坏的最后一个方块
private BlockPos lastStopMiningPos;
// 修复连续挖掘的标志位
private boolean isHackedBreak;
// 上一次停止挖掘包发出的时间
private int lastStopMiningTick;
public BukkitServerPlayer(BukkitCraftEngine plugin, @Nullable Channel channel) { public BukkitServerPlayer(BukkitCraftEngine plugin, @Nullable Channel channel) {
this.channel = channel; this.channel = channel;
@@ -518,8 +525,33 @@ public class BukkitServerPlayer extends Player {
if (this.gameTicks % 20 == 0) { if (this.gameTicks % 20 == 0) {
this.updateGUI(); this.updateGUI();
} }
if (this.isDestroyingBlock) { if (hasSwingHand()) {
this.tickBlockDestroy(); 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 (Config.predictBreaking() && !this.isDestroyingCustomBlock) {
// if it's not destroying blocks, we do predict // 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) { public void startMiningBlock(BlockPos pos, Object state, @Nullable ImmutableBlockState immutableBlockState) {
if (this.isHackedBreak) {
this.isHackedBreak = false;
this.abortMiningBlock();
}
// instant break // instant break
boolean custom = immutableBlockState != null; boolean custom = immutableBlockState != null;
if (custom && getDestroyProgress(state, pos) >= 1f) { if (custom && getDestroyProgress(state, pos) >= 1f) {
@@ -668,8 +704,11 @@ public class BukkitServerPlayer extends Player {
} }
} }
// 客户端觉得要停止破坏方块了
@Override @Override
public void stopMiningBlock() { public void stopMiningBlock() {
this.lastStopMiningPos = this.destroyPos;
this.lastStopMiningTick = gameTicks();
setClientSideCanBreakBlock(true); setClientSideCanBreakBlock(true);
setIsDestroyingBlock(false, false); setIsDestroyingBlock(false, false);
} }
@@ -705,8 +744,6 @@ public class BukkitServerPlayer extends Player {
private void tickBlockDestroy() { private void tickBlockDestroy() {
// if player swings hand is this tick // if player swings hand is this tick
if (!this.swingHandAck) return;
this.swingHandAck = false;
int currentTick = gameTicks(); int currentTick = gameTicks();
// optimize break speed, otherwise it would be too fast // optimize break speed, otherwise it would be too fast
if (currentTick - this.lastSuccessfulBreak <= 5) return; if (currentTick - this.lastSuccessfulBreak <= 5) return;
@@ -863,6 +900,11 @@ public class BukkitServerPlayer extends Player {
@Override @Override
public void onSwingHand() { public void onSwingHand() {
this.swingHandAck = true; this.swingHandAck = true;
this.lastSwingHandTick = gameTicks();
}
public boolean hasSwingHand() {
return this.swingHandAck && this.lastSwingHandTick + 2 > gameTicks();
} }
@Override @Override

View File

@@ -1,20 +1,37 @@
package net.momirealms.craftengine.bukkit.util; package net.momirealms.craftengine.bukkit.util;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; 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.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
public final class EnchantmentUtils { public final class EnchantmentUtils {
private EnchantmentUtils() {} private EnchantmentUtils() {}
@SuppressWarnings("unchecked")
public static List<Enchantment> toList(Object itemEnchantments) throws ReflectiveOperationException {
if (itemEnchantments == null) return List.of();
List<Enchantment> enchantmentList = new ArrayList<>();
Map<Object, Integer> enchantments = (Map<Object, Integer>) CoreReflections.field$ItemEnchantments$enchantments.get(itemEnchantments);
for (Map.Entry<Object, Integer> 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") @SuppressWarnings("unchecked")
public static Map<String, Integer> toMap(Object itemEnchantments) throws ReflectiveOperationException { public static Map<String, Integer> toMap(Object itemEnchantments) throws ReflectiveOperationException {
if (itemEnchantments == null) return Map.of(); if (itemEnchantments == null) return Map.of();
Map<String, Integer> map = new HashMap<>(); Map<String, Integer> map = new HashMap<>();
Map<Object, Integer> enchantments = (Map<Object, Integer>) CoreReflections.field$ItemEnchantments$enchantments.get(itemEnchantments); Map<Object, Integer> enchantments = (Map<Object, Integer>) CoreReflections.field$ItemEnchantments$enchantments.get(itemEnchantments);
for (Map.Entry<Object, Integer> entry : enchantments.entrySet()) { for (Map.Entry<Object, Integer> entry : enchantments.entrySet()) {
Object holder = entry.getKey(); Object holder = entry.getKey();
String name = (String) CoreReflections.method$Holder$getRegisteredName.invoke(holder); String name = (String) CoreReflections.method$Holder$getRegisteredName.invoke(holder);

View File

@@ -57,7 +57,13 @@ public class BukkitWorld implements World {
} }
@Override @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)); return new BukkitExistingBlock(platformWorld().getBlockAt(x, y, z));
} }
@@ -120,7 +126,7 @@ public class BukkitWorld implements World {
} }
@Override @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 worldServer = serverWorld();
Object blockPos = FastNMS.INSTANCE.constructor$BlockPos(x, y, z); Object blockPos = FastNMS.INSTANCE.constructor$BlockPos(x, y, z);
FastNMS.INSTANCE.method$LevelWriter$setBlock(worldServer, blockPos, blockState.literalObject(), flags); FastNMS.INSTANCE.method$LevelWriter$setBlock(worldServer, blockPos, blockState.literalObject(), flags);

View File

@@ -49,9 +49,6 @@ public class BukkitWorldManager implements WorldManager, Listener {
this.plugin = plugin; this.plugin = plugin;
this.worlds = ConcurrentUUID2ReferenceChainedHashTable.createWithCapacity(10, 0.5f); this.worlds = ConcurrentUUID2ReferenceChainedHashTable.createWithCapacity(10, 0.5f);
this.storageAdaptor = new DefaultStorageAdaptor(); this.storageAdaptor = new DefaultStorageAdaptor();
for (World world : Bukkit.getWorlds()) {
this.worlds.put(world.getUID(), new BukkitCEWorld(new BukkitWorld(world), this.storageAdaptor));
}
} }
@Override @Override
@@ -76,6 +73,11 @@ public class BukkitWorldManager implements WorldManager, Listener {
if (world != null) { if (world != null) {
this.lastWorldUUID = uuid; this.lastWorldUUID = uuid;
this.lastWorld = world; this.lastWorld = world;
} else {
World bukkitWorld = Bukkit.getWorld(uuid);
if (bukkitWorld != null) {
world = this.loadWorld(new BukkitWorld(bukkitWorld));
}
} }
return world; return world;
} }
@@ -90,7 +92,7 @@ public class BukkitWorldManager implements WorldManager, Listener {
} }
public void delayedInit() { public void delayedInit() {
// load loaded chunks // 此时大概率为空,暂且保留代码
for (World world : Bukkit.getWorlds()) { for (World world : Bukkit.getWorlds()) {
BukkitWorld wrappedWorld = new BukkitWorld(world); BukkitWorld wrappedWorld = new BukkitWorld(world);
try { try {
@@ -132,15 +134,38 @@ public class BukkitWorldManager implements WorldManager, Listener {
this.lastWorldUUID = null; 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) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onWorldLoad(WorldLoadEvent event) { 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 @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(); 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); CEWorld ceWorld = new BukkitCEWorld(world, this.storageAdaptor);
this.worlds.put(uuid, ceWorld); this.worlds.put(uuid, ceWorld);
this.resetWorldArray(); this.resetWorldArray();
@@ -149,6 +174,7 @@ public class BukkitWorldManager implements WorldManager, Listener {
handleChunkLoad(ceWorld, chunk, false); handleChunkLoad(ceWorld, chunk, false);
} }
ceWorld.setTicking(true); ceWorld.setTicking(true);
return ceWorld;
} }
@Override @Override

1
client-mod Submodule

Submodule client-mod added at 5d958f3b4a

View File

@@ -8,6 +8,9 @@ update-checker: true
forced-locale: '' forced-locale: ''
# Filter configuration phase player disconnection logs # Filter configuration phase player disconnection logs
filter-configuration-phase-disconnect: false 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: resource-pack:
# This option determines the location of the generated resource pack # This option determines the location of the generated resource pack
@@ -99,7 +102,7 @@ resource-pack:
fix-atlas: true fix-atlas: true
# Optimize your resource pack by reducing its size without any quality loss. # Optimize your resource pack by reducing its size without any quality loss.
optimization: optimization:
enable: true enable: false
# .png # .png
texture: texture:
enable: true enable: true
@@ -403,6 +406,7 @@ network:
text-display: true # Modern Holograms text-display: true # Modern Holograms
item: true item: true
advancement: true advancement: true
player-chat: true
recipe: recipe:
# Master switch for custom recipes # Master switch for custom recipes

View File

@@ -1,15 +1,8 @@
items: items:
default:amethyst_torch: default:amethyst_torch:
material: nether_brick
data: data:
item-name: <!i><l10n:item.amethyst_torch> item-name: <!i><l10n:item.amethyst_torch>
model: texture: minecraft:block/custom/amethyst_torch
type: minecraft:model
path: minecraft:item/custom/amethyst_torch
generation:
parent: minecraft:item/generated
textures:
layer0: minecraft:block/custom/amethyst_torch
behavior: behavior:
- type: wall_block_item - type: wall_block_item
block: default:amethyst_wall_torch block: default:amethyst_wall_torch
@@ -18,7 +11,6 @@ items:
- type: block_item - type: block_item
block: default:amethyst_wall_torch block: default:amethyst_wall_torch
default:amethyst_standing_torch: default:amethyst_standing_torch:
material: nether_brick
data: data:
item-name: <!i><l10n:item.amethyst_torch> item-name: <!i><l10n:item.amethyst_torch>
model: model:
@@ -29,7 +21,6 @@ items:
textures: textures:
torch: minecraft:block/custom/amethyst_torch torch: minecraft:block/custom/amethyst_torch
default:amethyst_wall_torch: default:amethyst_wall_torch:
material: nether_brick
data: data:
item-name: <!i><l10n:item.amethyst_torch> item-name: <!i><l10n:item.amethyst_torch>
model: model:

View File

@@ -3,11 +3,7 @@ items:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><l10n:item.chessboard_block> item-name: <!i><l10n:item.chessboard_block>
model: model: minecraft:block/custom/chessboard_block
type: minecraft:model
path: minecraft:item/custom/chessboard_block
generation:
parent: minecraft:block/custom/chessboard_block
behavior: behavior:
type: block_item type: block_item
block: block:

View File

@@ -3,11 +3,7 @@ items:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><l10n:item.chinese_lantern> item-name: <!i><l10n:item.chinese_lantern>
model: model: minecraft:block/custom/chinese_lantern
type: minecraft:model
path: minecraft:item/custom/chinese_lantern
generation:
parent: minecraft:block/custom/chinese_lantern
behavior: behavior:
type: block_item type: block_item
block: block:

View File

@@ -3,11 +3,7 @@ items:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><l10n:item.copper_coil> item-name: <!i><l10n:item.copper_coil>
model: model: minecraft:block/custom/copper_coil
type: minecraft:model
path: minecraft:item/custom/copper_coil
generation:
parent: minecraft:block/custom/copper_coil
behavior: behavior:
type: block_item type: block_item
block: block:
@@ -16,7 +12,6 @@ items:
settings: settings:
template: template:
- default:sound/metal - default:sound/metal
- default:pickaxe_power/level_1
overrides: overrides:
hardness: 3.0 hardness: 3.0
resistance: 4.5 resistance: 4.5
@@ -27,6 +22,8 @@ items:
map-color: 15 map-color: 15
tags: tags:
- minecraft:mineable/pickaxe - minecraft:mineable/pickaxe
correct-tools:
template: default:pickaxe_power/level_1
behavior: behavior:
type: lamp_block type: lamp_block
states: states:

View File

@@ -3,10 +3,7 @@ items:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><l10n:item.ender_pearl_flower_seeds> item-name: <!i><l10n:item.ender_pearl_flower_seeds>
model: texture: minecraft:item/custom/ender_pearl_flower_seeds
template: default:model/simplified_generated
arguments:
path: minecraft:item/custom/ender_pearl_flower_seeds
behavior: behavior:
type: block_item type: block_item
block: default:ender_pearl_flower block: default:ender_pearl_flower

View File

@@ -3,10 +3,7 @@ items:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><l10n:item.fairy_flower> item-name: <!i><l10n:item.fairy_flower>
model: texture: minecraft:item/custom/fairy_flower
template: default:model/simplified_generated
arguments:
path: minecraft:item/custom/fairy_flower
behavior: behavior:
type: block_item type: block_item
block: block:

View File

@@ -3,10 +3,7 @@ items:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><l10n:item.flame_cane> item-name: <!i><l10n:item.flame_cane>
model: texture: minecraft:item/custom/flame_cane
template: default:model/simplified_generated
arguments:
path: minecraft:item/custom/flame_cane
behavior: behavior:
type: block_item type: block_item
block: block:

View File

@@ -3,11 +3,7 @@ items:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><l10n:item.gunpowder_block> item-name: <!i><l10n:item.gunpowder_block>
model: model: minecraft:block/custom/gunpowder_block
type: minecraft:model
path: minecraft:item/custom/gunpowder_block
generation:
parent: minecraft:block/custom/gunpowder_block
behavior: behavior:
type: block_item type: block_item
block: block:
@@ -51,13 +47,14 @@ items:
settings: settings:
template: template:
- default:sound/stone - default:sound/stone
- default:pickaxe_power/level_1
- default:settings/solid_1x1x1 - default:settings/solid_1x1x1
overrides: overrides:
hardness: 1.8 hardness: 1.8
resistance: 1.8 resistance: 1.8
instrument: basedrum instrument: basedrum
map-color: 45 map-color: 45
correct-tools:
template: default:pickaxe_power/level_1
state: state:
auto-state: solid auto-state: solid
model: model:

View File

@@ -1,6 +1,7 @@
items: items:
default:hami_melon_slice: default:hami_melon_slice:
material: melon_slice material: melon_slice
texture: minecraft:item/custom/hami_melon_slice
data: data:
item-name: <!i><l10n:item.hami_melon_slice> item-name: <!i><l10n:item.hami_melon_slice>
$$>=1.20.5: $$>=1.20.5:
@@ -13,18 +14,11 @@ items:
food: food:
nutrition: 2 nutrition: 2
saturation: 1.0 saturation: 1.0
model:
template: default:model/simplified_generated
arguments:
path: minecraft:item/custom/hami_melon_slice
default:hami_melon: default:hami_melon:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><l10n:item.hami_melon> item-name: <!i><l10n:item.hami_melon>
model: model: minecraft:block/custom/hami_melon
path: minecraft:item/custom/hami_melon
generation:
parent: minecraft:block/custom/hami_melon
behavior: behavior:
type: block_item type: block_item
block: default:hami_melon block: default:hami_melon
@@ -32,10 +26,7 @@ items:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><l10n:item.hami_melon_seeds> item-name: <!i><l10n:item.hami_melon_seeds>
model: texture: minecraft:item/custom/hami_melon_seeds
template: default:model/simplified_generated
arguments:
path: minecraft:item/custom/hami_melon_seeds
behavior: behavior:
type: block_item type: block_item
block: default:hami_melon_stem block: default:hami_melon_stem

View File

@@ -1,10 +1,7 @@
items: items:
default:magma_fruit: default:magma_fruit:
material: carrot material: carrot
model: texture: minecraft:item/custom/magma_fruit
template: default:model/simplified_generated
arguments:
path: minecraft:item/custom/magma_fruit
data: data:
item-name: <!i><white><l10n:item.magma_fruit> item-name: <!i><white><l10n:item.magma_fruit>
$$>=1.20.5: $$>=1.20.5:

View File

@@ -1,13 +1,8 @@
items: items:
default:netherite_anvil: default:netherite_anvil:
material: nether_brick
data: data:
item-name: <!i><l10n:item.netherite_anvil> item-name: <!i><l10n:item.netherite_anvil>
model: model: minecraft:block/custom/netherite_anvil
type: minecraft:model
path: minecraft:item/custom/netherite_anvil
generation:
parent: minecraft:block/custom/netherite_anvil
behavior: behavior:
type: block_item type: block_item
block: block:
@@ -30,21 +25,19 @@ items:
- type: expression - type: expression
expression: '!<arg:player.is_sneaking>' expression: '!<arg:player.is_sneaking>'
settings: settings:
template: sounds:
- default:pickaxe_power/level_4 break: minecraft:block.anvil.break
overrides: step: minecraft:block.anvil.step
tags: place: minecraft:block.anvil.place
- minecraft:mineable/pickaxe hit: minecraft:block.anvil.hit
sounds: fall: minecraft:block.anvil.fall
break: minecraft:block.anvil.break map-color: 29
step: minecraft:block.anvil.step hardness: 10.0
place: minecraft:block.anvil.place resistance: 1200
hit: minecraft:block.anvil.hit push-reaction: block
fall: minecraft:block.anvil.fall correct-tools:
map-color: 29 template: default:pickaxe_power/level_4
hardness: 10.0 tags: ["minecraft:mineable/pickaxe"]
resistance: 1200
push-reaction: block
states: states:
properties: properties:
facing_clockwise: facing_clockwise:

View File

@@ -9,11 +9,7 @@ items:
- minecraft:logs_that_burn - minecraft:logs_that_burn
data: data:
item-name: <!i><l10n:item.palm_log> item-name: <!i><l10n:item.palm_log>
model: model: minecraft:block/custom/palm_log
type: minecraft:model
path: minecraft:item/custom/palm_log
generation:
parent: minecraft:block/custom/palm_log
behavior: behavior:
type: block_item type: block_item
block: block:
@@ -41,11 +37,7 @@ items:
- minecraft:logs_that_burn - minecraft:logs_that_burn
data: data:
item-name: <!i><l10n:item.stripped_palm_log> item-name: <!i><l10n:item.stripped_palm_log>
model: model: minecraft:block/custom/stripped_palm_log
type: minecraft:model
path: minecraft:item/custom/stripped_palm_log
generation:
parent: minecraft:block/custom/stripped_palm_log
behavior: behavior:
type: block_item type: block_item
block: block:
@@ -70,11 +62,7 @@ items:
- minecraft:logs_that_burn - minecraft:logs_that_burn
data: data:
item-name: <!i><l10n:item.palm_wood> item-name: <!i><l10n:item.palm_wood>
model: model: minecraft:block/custom/palm_wood
type: minecraft:model
path: minecraft:item/custom/palm_wood
generation:
parent: minecraft:block/custom/palm_wood
behavior: behavior:
type: block_item type: block_item
block: block:
@@ -102,11 +90,7 @@ items:
- minecraft:logs_that_burn - minecraft:logs_that_burn
data: data:
item-name: <!i><l10n:item.stripped_palm_wood> item-name: <!i><l10n:item.stripped_palm_wood>
model: model: minecraft:block/custom/stripped_palm_wood
type: minecraft:model
path: minecraft:item/custom/stripped_palm_wood
generation:
parent: minecraft:block/custom/stripped_palm_wood
behavior: behavior:
type: block_item type: block_item
block: block:
@@ -130,11 +114,7 @@ items:
- minecraft:wooden_tool_materials - minecraft:wooden_tool_materials
data: data:
item-name: <!i><l10n:item.palm_planks> item-name: <!i><l10n:item.palm_planks>
model: model: minecraft:block/custom/palm_planks
type: minecraft:model
path: minecraft:item/custom/palm_planks
generation:
parent: minecraft:block/custom/palm_planks
behavior: behavior:
type: block_item type: block_item
block: block:
@@ -157,11 +137,7 @@ items:
lore: lore:
- "<!i><gray>Requires the datapack tree configuration to function." - "<!i><gray>Requires the datapack tree configuration to function."
- "<!i><gray>If not configured, an oak tree will grow by default." - "<!i><gray>If not configured, an oak tree will grow by default."
model: texture: minecraft:block/custom/palm_sapling
template: default:model/generated
arguments:
model: minecraft:item/custom/palm_sapling
texture: minecraft:block/custom/palm_sapling
behavior: behavior:
type: block_item type: block_item
block: block:
@@ -230,11 +206,7 @@ items:
item-name: <!i><l10n:item.palm_trapdoor> item-name: <!i><l10n:item.palm_trapdoor>
settings: settings:
fuel-time: 300 fuel-time: 300
model: model: minecraft:block/custom/palm_trapdoor_bottom
type: minecraft:model
path: minecraft:item/custom/palm_trapdoor
generation:
parent: minecraft:block/custom/palm_trapdoor_bottom
behavior: behavior:
type: block_item type: block_item
block: block:
@@ -284,10 +256,7 @@ items:
item-name: <!i><l10n:item.palm_door> item-name: <!i><l10n:item.palm_door>
settings: settings:
fuel-time: 200 fuel-time: 200
model: texture: minecraft:item/custom/palm_door
template: default:model/simplified_generated
arguments:
path: minecraft:item/custom/palm_door
behavior: behavior:
type: double_high_block_item type: double_high_block_item
block: block:
@@ -358,11 +327,7 @@ items:
item-name: <!i><l10n:item.palm_fence_gate> item-name: <!i><l10n:item.palm_fence_gate>
settings: settings:
fuel-time: 300 fuel-time: 300
model: model: minecraft:block/custom/palm_fence_gate
type: minecraft:model
path: minecraft:item/custom/palm_fence_gate
generation:
parent: minecraft:block/custom/palm_fence_gate
behavior: behavior:
type: block_item type: block_item
block: block:
@@ -414,11 +379,7 @@ items:
item-name: <!i><l10n:item.palm_slab> item-name: <!i><l10n:item.palm_slab>
settings: settings:
fuel-time: 150 fuel-time: 150
model: model: minecraft:block/custom/palm_slab
type: minecraft:model
path: minecraft:item/custom/palm_slab
generation:
parent: minecraft:block/custom/palm_slab
behavior: behavior:
type: block_item type: block_item
block: block:
@@ -456,11 +417,7 @@ items:
model_double_path: minecraft:block/custom/palm_planks model_double_path: minecraft:block/custom/palm_planks
default:palm_stairs: default:palm_stairs:
material: nether_brick material: nether_brick
model: model: minecraft:block/custom/palm_stairs
type: minecraft:model
path: minecraft:item/custom/palm_stairs
generation:
parent: minecraft:block/custom/palm_stairs
data: data:
item-name: <!i><l10n:item.palm_stairs> item-name: <!i><l10n:item.palm_stairs>
settings: settings:
@@ -505,11 +462,7 @@ items:
textures: *textures textures: *textures
default:palm_pressure_plate: default:palm_pressure_plate:
material: nether_brick material: nether_brick
model: model: minecraft:block/custom/palm_pressure_plate
type: minecraft:model
path: minecraft:item/custom/palm_pressure_plate
generation:
parent: minecraft:block/custom/palm_pressure_plate
data: data:
item-name: <!i><l10n:item.palm_pressure_plate> item-name: <!i><l10n:item.palm_pressure_plate>
settings: settings:
@@ -693,15 +646,15 @@ recipes:
default:palm_planks: default:palm_planks:
template: default:recipe/planks template: default:recipe/planks
arguments: arguments:
wood_type: palm wood_type: default:palm
default:palm_wood: default:palm_wood:
template: default:recipe/log_2_wood template: default:recipe/log_2_wood
arguments: arguments:
wood_type: palm wood_type: default:palm
default:stripped_palm_wood: default:stripped_palm_wood:
template: default:recipe/log_2_wood template: default:recipe/log_2_wood
arguments: arguments:
wood_type: stripped_palm wood_type: default:stripped_palm
default:palm_trapdoor: default:palm_trapdoor:
type: shaped type: shaped
pattern: pattern:

View File

@@ -3,10 +3,7 @@ items:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><l10n:item.pebble> item-name: <!i><l10n:item.pebble>
model: texture: minecraft:item/custom/pebble
template: default:model/simplified_generated
arguments:
path: minecraft:item/custom/pebble
behavior: behavior:
- type: block_item - type: block_item
block: block:

View File

@@ -3,10 +3,7 @@ items:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><l10n:item.reed> item-name: <!i><l10n:item.reed>
model: texture: minecraft:item/custom/reed
template: default:model/simplified_generated
arguments:
path: minecraft:item/custom/reed
behavior: behavior:
type: liquid_collision_block_item type: liquid_collision_block_item
block: block:

View File

@@ -3,11 +3,7 @@ items:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><l10n:item.safe_block> item-name: <!i><l10n:item.safe_block>
model: model: minecraft:block/custom/safe_block
type: minecraft:model
path: minecraft:item/custom/safe_block
generation:
parent: minecraft:block/custom/safe_block
behavior: behavior:
type: block_item type: block_item
block: block:

View File

@@ -3,9 +3,7 @@ items:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><l10n:item.sofa> item-name: <!i><l10n:item.sofa>
model: model: minecraft:item/custom/sleeper_sofa
type: minecraft:model
path: minecraft:item/custom/sleeper_sofa
behavior: behavior:
type: block_item type: block_item
block: block:
@@ -44,9 +42,7 @@ items:
item: default:sleeper_sofa item: default:sleeper_sofa
default:sofa_inner: default:sofa_inner:
material: nether_brick material: nether_brick
model: model: minecraft:item/custom/sofa_inner
type: minecraft:model
path: minecraft:item/custom/sofa_inner
default:sofa: default:sofa:
material: nether_brick material: nether_brick
data: data:

View File

@@ -3,9 +3,7 @@ items:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><l10n:item.table_lamp> item-name: <!i><l10n:item.table_lamp>
model: model: minecraft:item/custom/table_lamp
type: minecraft:model
path: minecraft:item/custom/table_lamp
behavior: behavior:
type: block_item type: block_item
block: block:

View File

@@ -3,11 +3,7 @@ items:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><l10n:item.topaz_ore> item-name: <!i><l10n:item.topaz_ore>
model: model: minecraft:block/custom/topaz_ore
type: minecraft:model
path: minecraft:item/custom/topaz_ore
generation:
parent: minecraft:block/custom/topaz_ore
behavior: behavior:
type: block_item type: block_item
block: default:topaz_ore block: default:topaz_ore
@@ -15,11 +11,7 @@ items:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><l10n:item.deepslate_topaz_ore> item-name: <!i><l10n:item.deepslate_topaz_ore>
model: model: minecraft:block/custom/deepslate_topaz_ore
type: minecraft:model
path: minecraft:item/custom/deepslate_topaz_ore
generation:
parent: minecraft:block/custom/deepslate_topaz_ore
behavior: behavior:
type: block_item type: block_item
block: default:deepslate_topaz_ore block: default:deepslate_topaz_ore
@@ -32,10 +24,7 @@ items:
percent: 0.25 percent: 0.25
data: data:
item-name: <!i><#FF8C00><l10n:item.topaz> item-name: <!i><#FF8C00><l10n:item.topaz>
model: texture: minecraft:item/custom/topaz
template: default:model/simplified_generated
arguments:
path: minecraft:item/custom/topaz
blocks: blocks:
default:topaz_ore: default:topaz_ore:
loot: loot:
@@ -75,26 +64,42 @@ blocks:
path: minecraft:block/custom/deepslate_topaz_ore path: minecraft:block/custom/deepslate_topaz_ore
recipes: recipes:
default:topaz_from_smelting_topaz_ore: default:topaz_from_smelting_topaz_ore:
template: default:recipe/smelting_ore type: smelting
arguments: experience: 1.0
exp: 1.0 category: misc
ingredient: default:topaz_ore group: topaz
result: default:topaz time: 200
ingredient: default:topaz_ore
result:
id: default:topaz
count: 1
default:topaz_from_smelting_deepslate_topaz_ore: default:topaz_from_smelting_deepslate_topaz_ore:
template: default:recipe/smelting_ore type: smelting
arguments: experience: 1.0
exp: 1.0 category: misc
ingredient: default:deepslate_topaz_ore group: topaz
result: default:topaz time: 200
ingredient: default:deepslate_topaz_ore
result:
id: default:topaz
count: 1
default:topaz_from_blasting_topaz_ore: default:topaz_from_blasting_topaz_ore:
template: default:recipe/blasting_ore type: blasting
arguments: experience: 1.0
exp: 1.0 category: misc
ingredient: default:topaz_ore group: topaz
result: default:topaz time: 100
ingredient: default:topaz_ore
result:
id: default:topaz
count: 1
default:topaz_from_blasting_deepslate_topaz_ore: default:topaz_from_blasting_deepslate_topaz_ore:
template: default:recipe/blasting_ore type: blasting
arguments: experience: 1.0
exp: 1.0 category: misc
ingredient: default:deepslate_topaz_ore group: topaz
result: default:topaz time: 100
ingredient: default:deepslate_topaz_ore
result:
id: default:topaz
count: 1

View File

@@ -1,6 +1,6 @@
templates: templates:
default:emoji/basic: default:emoji/basic:
content: <hover:show_text:'<l10n:emoji.tip>'><!shadow><white><arg:emoji></white></!shadow></hover> content: <hover:show_text:'<i18n:emoji.tip>'><!shadow><white><arg:emoji></white></!shadow></hover>
emoji: emoji:
default:emoji_smiley: default:emoji_smiley:
template: default:emoji/basic template: default:emoji/basic

View File

@@ -3,9 +3,7 @@ items:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><l10n:item.bench> item-name: <!i><l10n:item.bench>
model: model: minecraft:item/custom/bench
type: minecraft:model
path: minecraft:item/custom/bench
behavior: behavior:
type: furniture_item type: furniture_item
furniture: furniture:

View File

@@ -3,28 +3,19 @@ items:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><l10n:item.flower_basket> item-name: <!i><l10n:item.flower_basket>
model: texture: minecraft:item/custom/flower_basket_2d
template: default:model/simplified_generated
arguments:
path: minecraft:item/custom/flower_basket_2d
behavior: behavior:
type: furniture_item type: furniture_item
furniture: default:flower_basket furniture: default:flower_basket
default:flower_basket_ground: default:flower_basket_ground:
material: nether_brick material: nether_brick
model: model: minecraft:item/custom/flower_basket_ground
type: minecraft:model
path: minecraft:item/custom/flower_basket_ground
default:flower_basket_wall: default:flower_basket_wall:
material: nether_brick material: nether_brick
model: model: minecraft:item/custom/flower_basket_wall
type: minecraft:model
path: minecraft:item/custom/flower_basket_wall
default:flower_basket_ceiling: default:flower_basket_ceiling:
material: nether_brick material: nether_brick
model: model: minecraft:item/custom/flower_basket_ceiling
type: minecraft:model
path: minecraft:item/custom/flower_basket_ceiling
furniture: furniture:
default:flower_basket: default:flower_basket:
settings: settings:

View File

@@ -3,9 +3,7 @@ items:
material: nether_brick material: nether_brick
data: data:
item-name: <!i><l10n:item.wooden_chair> item-name: <!i><l10n:item.wooden_chair>
model: model: minecraft:item/custom/wooden_chair
type: minecraft:model
path: minecraft:item/custom/wooden_chair
behavior: behavior:
type: furniture_item type: furniture_item
furniture: furniture:

View File

@@ -9,8 +9,6 @@ items:
wings: flame_elytra wings: flame_elytra
data: data:
item-name: <!i><#FF8C00><l10n:item.flame_elytra> item-name: <!i><#FF8C00><l10n:item.flame_elytra>
model: textures:
template: default:model/simplified_elytra - minecraft:item/custom/flame_elytra
arguments: - minecraft:item/custom/flame_elytra_broken
path: minecraft:item/custom/flame_elytra
broken_path: minecraft:item/custom/broken_flame_elytra

View File

@@ -14,6 +14,8 @@ templates:
slot: ${slot} slot: ${slot}
model: model:
template: default:model/armor_trim template: default:model/armor_trim
arguments:
texture: minecraft:item/custom/topaz_${part}
items: items:
default:topaz_helmet: default:topaz_helmet:
template: template:

View File

@@ -7,11 +7,9 @@ items:
data: data:
item-name: <!i><#FF8C00><l10n:item.topaz_rod> item-name: <!i><#FF8C00><l10n:item.topaz_rod>
tooltip-style: minecraft:topaz tooltip-style: minecraft:topaz
model: textures:
template: default:model/simplified_fishing_rod_2d - minecraft:item/custom/topaz_rod
arguments: - minecraft:item/custom/topaz_rod_cast
path: minecraft:item/custom/topaz_rod
cast_path: minecraft:item/custom/topaz_rod_cast
default:topaz_bow: default:topaz_bow:
material: bow material: bow
settings: settings:
@@ -20,13 +18,11 @@ items:
data: data:
item-name: <!i><#FF8C00><l10n:item.topaz_bow> item-name: <!i><#FF8C00><l10n:item.topaz_bow>
tooltip-style: minecraft:topaz tooltip-style: minecraft:topaz
model: textures:
template: default:model/simplified_bow_2d - minecraft:item/custom/topaz_bow
arguments: - minecraft:item/custom/topaz_bow_pulling_0
path: minecraft:item/custom/topaz_bow - minecraft:item/custom/topaz_bow_pulling_1
pulling_0_path: minecraft:item/custom/topaz_bow_pulling_0 - minecraft:item/custom/topaz_bow_pulling_2
pulling_1_path: minecraft:item/custom/topaz_bow_pulling_1
pulling_2_path: minecraft:item/custom/topaz_bow_pulling_2
default:topaz_crossbow: default:topaz_crossbow:
material: crossbow material: crossbow
settings: settings:
@@ -35,15 +31,13 @@ items:
data: data:
item-name: <!i><#FF8C00><l10n:item.topaz_crossbow> item-name: <!i><#FF8C00><l10n:item.topaz_crossbow>
tooltip-style: minecraft:topaz tooltip-style: minecraft:topaz
model: textures:
template: default:model/simplified_crossbow_2d - minecraft:item/custom/topaz_crossbow
arguments: - minecraft:item/custom/topaz_crossbow_pulling_0
path: minecraft:item/custom/topaz_crossbow - minecraft:item/custom/topaz_crossbow_pulling_1
pulling_0_path: minecraft:item/custom/topaz_crossbow_pulling_0 - minecraft:item/custom/topaz_crossbow_pulling_2
pulling_1_path: minecraft:item/custom/topaz_crossbow_pulling_1 - minecraft:item/custom/topaz_crossbow_arrow
pulling_2_path: minecraft:item/custom/topaz_crossbow_pulling_2 - minecraft:item/custom/topaz_crossbow_firework
arrow_path: minecraft:item/custom/topaz_crossbow_arrow
firework_path: minecraft:item/custom/topaz_crossbow_firework
default:topaz_pickaxe: default:topaz_pickaxe:
material: golden_pickaxe material: golden_pickaxe
settings: settings:
@@ -53,10 +47,7 @@ items:
item-name: <!i><#FF8C00><l10n:item.topaz_pickaxe> item-name: <!i><#FF8C00><l10n:item.topaz_pickaxe>
tooltip-style: minecraft:topaz tooltip-style: minecraft:topaz
max-damage: 64 max-damage: 64
model: texture: minecraft:item/custom/topaz_pickaxe
template: default:model/simplified_handheld
arguments:
path: minecraft:item/custom/topaz_pickaxe
default:topaz_axe: default:topaz_axe:
material: golden_axe material: golden_axe
settings: settings:
@@ -66,10 +57,7 @@ items:
item-name: <!i><#FF8C00><l10n:item.topaz_axe> item-name: <!i><#FF8C00><l10n:item.topaz_axe>
tooltip-style: minecraft:topaz tooltip-style: minecraft:topaz
max-damage: 64 max-damage: 64
model: texture: minecraft:item/custom/topaz_axe
template: default:model/simplified_handheld
arguments:
path: minecraft:item/custom/topaz_axe
default:topaz_hoe: default:topaz_hoe:
material: golden_hoe material: golden_hoe
settings: settings:
@@ -79,36 +67,25 @@ items:
item-name: <!i><#FF8C00><l10n:item.topaz_hoe> item-name: <!i><#FF8C00><l10n:item.topaz_hoe>
tooltip-style: minecraft:topaz tooltip-style: minecraft:topaz
max-damage: 64 max-damage: 64
model: texture: minecraft:item/custom/topaz_hoe
template: default:model/simplified_handheld
arguments:
path: minecraft:item/custom/topaz_hoe
default:topaz_shovel: default:topaz_shovel:
material: golden_shovel material: golden_shovel
settings: settings:
tags: tags: ["default:topaz_tools"]
- default:topaz_tools
data: data:
item-name: <!i><#FF8C00><l10n:item.topaz_shovel> item-name: <!i><#FF8C00><l10n:item.topaz_shovel>
tooltip-style: minecraft:topaz tooltip-style: minecraft:topaz
max-damage: 64 max-damage: 64
model: texture: minecraft:item/custom/topaz_shovel
template: default:model/simplified_handheld
arguments:
path: minecraft:item/custom/topaz_shovel
default:topaz_sword: default:topaz_sword:
material: golden_sword material: golden_sword
settings: settings:
tags: tags: ["default:topaz_tools"]
- default:topaz_tools
data: data:
item-name: <!i><#FF8C00><l10n:item.topaz_sword> item-name: <!i><#FF8C00><l10n:item.topaz_sword>
tooltip-style: minecraft:topaz tooltip-style: minecraft:topaz
max-damage: 64 max-damage: 64
model: texture: minecraft:item/custom/topaz_sword
template: default:model/simplified_handheld
arguments:
path: minecraft:item/custom/topaz_sword
$$>=1.21.4#topaz_trident: $$>=1.21.4#topaz_trident:
default:topaz_trident: default:topaz_trident:
material: trident material: trident

View File

@@ -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

View File

@@ -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

View File

@@ -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}

View File

@@ -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

View File

@@ -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

View File

@@ -220,6 +220,8 @@ warning.config.item.legacy_model.missing_path: "<yellow>Issue found in file <arg
warning.config.item.legacy_model.overrides.missing_path: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is missing the require 'path' argument for legacy-model overrides.</yellow>" warning.config.item.legacy_model.overrides.missing_path: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is missing the require 'path' argument for legacy-model overrides.</yellow>"
warning.config.item.legacy_model.overrides.missing_predicate: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is missing the require 'predicate' argument for legacy-model overrides.</yellow>" warning.config.item.legacy_model.overrides.missing_predicate: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is missing the require 'predicate' argument for legacy-model overrides.</yellow>"
warning.config.item.legacy_model.cannot_convert: "<yellow>Issue found in file <arg:0> - Cannot convert 1.21.4+ items to legacy format for item '<arg:1>'. Please manually create 'legacy-model' section for this item.</yellow>" warning.config.item.legacy_model.cannot_convert: "<yellow>Issue found in file <arg:0> - Cannot convert 1.21.4+ items to legacy format for item '<arg:1>'. Please manually create 'legacy-model' section for this item.</yellow>"
warning.config.item.simplified_model.invalid_model: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' contains a mismatched number of parameters. The expected number of models is '<arg:2>', but the actual number is '<arg:3>'.</yellow>"
warning.config.item.simplified_model.invalid_texture: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' contains a mismatched number of parameters. The expected number of textures is '<arg:2>', but the actual number is '<arg:3>'.</yellow>"
warning.config.item.model.invalid_type: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is using an invalid model type '<arg:2>'.</yellow>" warning.config.item.model.invalid_type: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is using an invalid model type '<arg:2>'.</yellow>"
warning.config.item.model.tint.missing_type: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is missing the required 'type' argument for tint.</yellow>" warning.config.item.model.tint.missing_type: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is missing the required 'type' argument for tint.</yellow>"
warning.config.item.model.tint.invalid_type: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is using an invalid tint type '<arg:2>'.</yellow>" warning.config.item.model.tint.invalid_type: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is using an invalid tint type '<arg:2>'.</yellow>"
@@ -353,6 +355,8 @@ warning.config.block.behavior.attached_stem.missing_facing: "<yellow>Issue found
warning.config.block.behavior.attached_stem.missing_fruit: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'fruit' argument for 'attached_stem_block' behavior.</yellow>" warning.config.block.behavior.attached_stem.missing_fruit: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'fruit' argument for 'attached_stem_block' behavior.</yellow>"
warning.config.block.behavior.attached_stem.missing_stem: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'stem' argument for 'attached_stem_block' behavior.</yellow>" warning.config.block.behavior.attached_stem.missing_stem: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'stem' argument for 'attached_stem_block' behavior.</yellow>"
warning.config.block.behavior.chime.missing_sounds_projectile_hit: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'sounds.projectile-hit' argument for 'chime_block' behavior.</yellow>" warning.config.block.behavior.chime.missing_sounds_projectile_hit: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'sounds.projectile-hit' argument for 'chime_block' behavior.</yellow>"
warning.config.block.behavior.surface_spreading.missing_base_block: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'base-block' argument for 'surface_spreading_block' behavior.</yellow>"
warning.config.block.behavior.snowy.missing_snowy: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'snowy' property for 'snowy_block' behavior.</yellow>"
warning.config.model.generation.missing_parent: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'parent' argument in 'generation' section.</yellow>" warning.config.model.generation.missing_parent: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'parent' argument in 'generation' section.</yellow>"
warning.config.model.generation.conflict: "<yellow>Issue found in file <arg:0> - Failed to generate model for '<arg:1>' as two or more configurations attempt to generate different json models with the same path: '<arg:2>'.</yellow>" warning.config.model.generation.conflict: "<yellow>Issue found in file <arg:0> - Failed to generate model for '<arg:1>' as two or more configurations attempt to generate different json models with the same path: '<arg:2>'.</yellow>"
warning.config.model.generation.invalid_display_position: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid display position '<arg:2>' in 'generation.display' section. Allowed display positions: [<arg:3>]</yellow>" warning.config.model.generation.invalid_display_position: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid display position '<arg:2>' in 'generation.display' section. Allowed display positions: [<arg:3>]</yellow>"
@@ -477,6 +481,7 @@ warning.config.function.when.missing_source: "<yellow>Issue found in file <arg:0
warning.config.function.if_else.missing_rules: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'rules' argument for 'if_else' function.</yellow>" warning.config.function.if_else.missing_rules: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'rules' argument for 'if_else' function.</yellow>"
warning.config.function.update_block_property.missing_properties: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'properties' argument for 'update_block_property' function.</yellow>" warning.config.function.update_block_property.missing_properties: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'properties' argument for 'update_block_property' function.</yellow>"
warning.config.function.transform_block.missing_block: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'block' argument for 'transform_block' function.</yellow>" warning.config.function.transform_block.missing_block: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'block' argument for 'transform_block' function.</yellow>"
warning.config.function.cycle_block_property.missing_property: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'property' argument for 'cycle_block_property' function.</yellow>"
warning.config.selector.missing_type: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'type' argument for selector.</yellow>" warning.config.selector.missing_type: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'type' argument for selector.</yellow>"
warning.config.selector.invalid_type: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid selector type '<arg:2>'.</yellow>" warning.config.selector.invalid_type: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid selector type '<arg:2>'.</yellow>"
warning.config.selector.invalid_target: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid selector target '<arg:2>'.</yellow>" warning.config.selector.invalid_target: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid selector target '<arg:2>'.</yellow>"

View File

@@ -0,0 +1,505 @@
lang-version: "${lang_version}"
exception.invalid_syntax: "<red>Syntaxe invalide. Utilisation correcte : <white><arg:0></white></red>"
exception.invalid_argument: "<red>Argument invalide. Raison : <white><arg:0></white></red>"
exception.invalid_sender: "<red><arg:0> n'est pas autorisé à exécuter cette commande. Doit être de type <arg:1></red>"
exception.unexpected: "<red>Une erreur interne s'est produite lors de l'exécution de cette commande</red>"
exception.no_permission: "<red>Désolé, mais vous n'avez pas la permission d'utiliser cette commande</red>"
exception.no_such_command: "Commande inconnue."
argument.entity.notfound.player: "<red><lang:argument.entity.notfound.player></red>"
argument.entity.notfound.entity: "<red><lang:argument.entity.notfound.entity></red>"
argument.parse.failure.time: "<red>'<arg:0>' n'est pas un format de temps valide</red>"
argument.parse.failure.material: "<red>'<arg:0>' n'est pas un nom de matériau valide</red>"
argument.parse.failure.enchantment: "<red>'<arg:0>' n'est pas un enchantement valide</red>"
argument.parse.failure.offlineplayer: "<red>Aucun joueur trouvé pour l'entrée '<arg:0>'</red>"
argument.parse.failure.player: "<red>Aucun joueur trouvé pour l'entrée '<arg:0>'</red>"
argument.parse.failure.world: "<red>'<arg:0>' n'est pas un monde Minecraft valide</red>"
argument.parse.failure.location.invalid_format: "<red>'<arg:0>' n'est pas une position valide. Format requis : '<arg:1> <arg:2> <arg:3>'</red>"
argument.parse.failure.location.mixed_local_absolute: "<red>Impossible de mélanger coordonnées locales et absolues (soit toutes utilisent '^', soit aucune)</red>"
argument.parse.failure.namespacedkey.namespace: "<red>Espace de noms invalide '<arg:0>'. Doit correspondre à [a-z0-9._-]</red>"
argument.parse.failure.namespacedkey.key: "<red>Clé invalide '<arg:0>'. Doit correspondre à [a-z0-9/._-]</red>"
argument.parse.failure.namespacedkey.need_namespace: "<red>Entrée invalide '<arg:0>', un espace de noms explicite est requis</red>"
argument.parse.failure.boolean: "<red>Impossible d'interpréter un booléen depuis '<arg:0>'</red>"
argument.parse.failure.number: "<red>'<arg:0>' n'est pas un nombre valide dans lintervalle <arg:1> à <arg:2></red>"
argument.parse.failure.char: "<red>'<arg:0>' n'est pas un caractère valide</red>"
argument.parse.failure.string: "<red>'<arg:0>' n'est pas une chaîne valide de type <arg:1></red>"
argument.parse.failure.uuid: "<red>'<arg:0>' n'est pas un UUID valide</red>"
argument.parse.failure.enum: "<red>'<arg:0>' ne fait pas partie des options suivantes : <arg:1></red>"
argument.parse.failure.regex: "<red>'<arg:0>' ne correspond pas à '<arg:1>'</red>"
argument.parse.failure.flag.unknown: "<red>Indicateur inconnu '<arg:0>'</red>"
argument.parse.failure.flag.duplicate_flag: "<red>Indicateur dupliqué '<arg:0>'</red>"
argument.parse.failure.flag.no_flag_started: "<red>Aucun indicateur commencé. Impossible de traiter '<arg:0>'</red>"
argument.parse.failure.flag.missing_argument: "<red>Argument manquant pour '<arg:0>'</red>"
argument.parse.failure.flag.no_permission: "<red>Vous n'avez pas la permission d'utiliser '<arg:0>'</red>"
argument.parse.failure.color: "<red>'<arg:0>' n'est pas une couleur valide</red>"
argument.parse.failure.duration: "<red>'<arg:0>' n'est pas un format de durée valide</red>"
argument.parse.failure.aggregate.missing: "<red>Composant manquant '<arg:0>'</red>"
argument.parse.failure.aggregate.failure: "<red>Composant invalide '<arg:0>' : <arg:1></red>"
argument.parse.failure.either: "<red>Impossible de résoudre '<arg:0>' comme <arg:1> ou <arg:2></red>"
argument.parse.failure.namedtextcolor: "<red>'<arg:0>' n'est pas un nom de couleur de texte valide</red>"
command.reload.config.success: "<white>Configurations rechargées en <green><arg:0></green> ms.</white> <gray>(Asynchrone : <arg:1> ms | Synchrone : <arg:2> ms)</gray>"
command.reload.config.failure: "<red>Échec du rechargement de la configuration. Consultez les logs de la console.</red>"
command.reload.pack.success: "<white>Pack de ressources rechargé en <green><arg:0></green> ms.</white>"
command.reload.pack.failure: "<red>Échec du rechargement du pack de ressources. Consultez les logs de la console.</red>"
command.reload.all.success: "<white>Rechargement terminé en <green><arg:0></green> ms.</white> <gray>(Asynchrone : <arg:1> ms | Synchrone : <arg:2> ms | Pack : <arg:3> ms)</gray>"
command.reload.all.failure: "<red>Échec du rechargement. Consultez les logs de la console.</red>"
command.item.get.success: "<white>Obtenu <arg:0> de <arg:1></white>"
command.item.get.failure.not_exist: "<red><lang:argument.item.id.invalid:'<arg:0>'></red>"
command.item.give.success.single: "<lang:commands.give.success.single:'<arg:0>':'<arg:1>':'<arg:2>'>"
command.item.give.success.multiple: "<lang:commands.give.success.multiple:'<arg:0>':'<arg:1>':'<arg:2>'>"
command.item.give.failure.not_exist: "<red><lang:argument.item.id.invalid:'<arg:0>'></red>"
command.search_recipe.not_found: "<red>Aucune recette trouvée pour cet objet</red>"
command.search_usage.not_found: "<red>Aucune utilisation trouvée pour cet objet</red>"
command.search_recipe.no_item: "<red>Veuillez tenir un objet avant dexécuter cette commande</red>"
command.search_usage.no_item: "<red>Veuillez tenir un objet avant dexécuter cette commande</red>"
command.totem_animation.failure.not_totem: "<red>Lobjet '<arg:0>' nest pas minecraft:totem_of_undying</red>"
command.totem_animation.success.single: "<white>Animation de totem <arg:0> jouée pour <arg:1></white>"
command.totem_animation.success.multiple: "<white>Animation de totem <arg:0> jouée pour <arg:1> joueurs</white>"
command.resource.enable.success: "<white>Ressource <arg:0> activée. Exécutez <click:run_command:/ce reload all><u>/ce reload all</u></click> pour appliquer les changements</white>"
command.resource.enable.failure.unknown: "<red>Ressource inconnue <arg:0></red>"
command.resource.disable.success: "<white>Ressource <arg:0> désactivée. Exécutez <click:run_command:/ce reload all><u>/ce reload all</u></click> pour appliquer les changements</white>"
command.resource.disable.failure.unknown: "<red>Ressource inconnue <arg:0></red>"
command.resource.list: "<white>Ressources activées(<arg:0>): <green><arg:1></green><newline>Ressources désactivées(<arg:2>): <red><arg:3></red></white>"
command.upload.failure.not_supported: "<red>La méthode dhébergement actuelle '<arg:0>' ne prend pas en charge lenvoi de packs de ressources.</red>"
command.upload.on_progress: "<white>Téléversement démarré. Consultez la console pour plus dinformations.</white>"
command.send_resource_pack.success.single: "<white>Pack de ressources envoyé à <arg:0>.</white>"
command.send_resource_pack.success.multiple: "<white>Packs de ressources envoyés à <arg:0> joueurs.</white>"
command.locale.set.failure: "<red>Format de locale invalide : <arg:0></red>"
command.locale.set.success: "<white>Locale définie sur <arg:0> pour <arg:1></white>"
command.locale.unset.success: "<white>Locale réinitialisée pour <arg:0></white>"
warning.network.resource_pack.unverified_uuid: "<yellow>Le joueur <arg:0> tente de demander un pack de ressources avec un UUID (<arg:1>) qui nest pas authentifié par le serveur.</yellow>"
warning.config.pack.duplicated_files: "<red>Des fichiers dupliqués ont été trouvés. Veuillez les résoudre via la section 'resource-pack.duplicated-files-handler' dans config.yml.</red>"
warning.config.yaml.duplicated_key: "<red>Problème dans le fichier <arg:0> - Clé dupliquée '<arg:1>' détectée à la ligne <arg:2>, cela peut causer des résultats inattendus.</red>"
warning.config.yaml.inconsistent_value_type: "<red>Problème dans le fichier <arg:0> - Clé dupliquée '<arg:1>' détectée à la ligne <arg:2> avec des types de valeur différents, cela peut causer des résultats inattendus.</red>"
warning.config.type.int: "<yellow>Problème dans le fichier <arg:0> - Impossible de charger '<arg:1>': Impossible de convertir '<arg:2>' en entier pour loption '<arg:3>'.</yellow>"
warning.config.type.boolean: "<yellow>Problème dans le fichier <arg:0> - Impossible de charger '<arg:1>': Impossible de convertir '<arg:2>' en booléen pour loption '<arg:3>'.</yellow>"
warning.config.type.float: "<yellow>Problème dans le fichier <arg:0> - Impossible de charger '<arg:1>': Impossible de convertir '<arg:2>' en nombre décimal (float) pour loption '<arg:3>'.</yellow>"
warning.config.type.double: "<yellow>Problème dans le fichier <arg:0> - Impossible de charger '<arg:1>': Impossible de convertir '<arg:2>' en double pour loption '<arg:3>'.</yellow>"
warning.config.type.quaternionf: "<yellow>Problème dans le fichier <arg:0> - Impossible de charger '<arg:1>': Impossible de convertir '<arg:2>' en Quaternionf pour loption '<arg:3>'.</yellow>"
warning.config.type.vector3f: "<yellow>Problème dans le fichier <arg:0> - Impossible de charger '<arg:1>': Impossible de convertir '<arg:2>' en Vector3f pour loption '<arg:3>'.</yellow>"
warning.config.type.vec3d: "<yellow>Problème dans le fichier <arg:0> - Impossible de charger '<arg:1>': Impossible de convertir '<arg:2>' en Vec3d pour loption '<arg:3>'.</yellow>"
warning.config.type.map: "<yellow>Problème dans le fichier <arg:0> - Impossible de charger '<arg:1>': Impossible de convertir '<arg:2>' en type Map pour loption '<arg:3>'.</yellow>"
warning.config.type.snbt.invalid_syntax: "<yellow>Problème dans le fichier <arg:0> - Impossible de charger '<arg:1>': Syntaxe SNBT invalide '<arg:2>'.</yellow>"
warning.config.number.missing_type: "<yellow>Problème dans le fichier <arg:0> - La configuration '<arg:1>' na pas largument obligatoire 'type' pour un nombre.</yellow>"
warning.config.number.invalid_type: "<yellow>Problème dans le fichier <arg:0> - La configuration '<arg:1>' utilise un type de nombre invalide '<arg:2>'.</yellow>"
warning.config.number.missing_argument: "<yellow>Problème dans le fichier <arg:0> - La configuration '<arg:1>' na pas largument requis pour 'number'.</yellow>"
warning.config.number.invalid_format: "<yellow>Problème dans le fichier <arg:0> - La configuration '<arg:1>' utilise un format numérique invalide '<arg:2>'.</yellow>"
warning.config.number.fixed.missing_value: "<yellow>Problème dans le fichier <arg:0> - La configuration '<arg:1>' na pas la valeur requise pour un nombre constant ('value').</yellow>"
warning.config.number.fixed.invalid_value: "<yellow>Problème dans le fichier <arg:0> - La configuration '<arg:1>' utilise une valeur invalide '<arg:2>' pour un nombre constant.</yellow>"
warning.config.number.expression.missing_expression: "<yellow>Problème dans le fichier <arg:0> - La configuration '<arg:1>' na pas largument requis 'expression' pour un nombre de type expression.</yellow>"
warning.config.number.uniform.missing_min: "<yellow>Problème dans le fichier <arg:0> - La configuration '<arg:1>' na pas largument requis 'min' pour un nombre uniforme.</yellow>"
warning.config.number.uniform.missing_max: "<yellow>Problème dans le fichier <arg:0> - La configuration '<arg:1>' na pas largument requis 'max' pour un nombre uniforme.</yellow>"
warning.config.number.gaussian.missing_min: "<yellow>Problème dans le fichier <arg:0> - La configuration '<arg:1>' na pas largument requis 'min' pour un nombre gaussien.</yellow>"
warning.config.number.gaussian.missing_max: "<yellow>Problème dans le fichier <arg:0> - La configuration '<arg:1>' na pas largument requis 'max' pour un nombre gaussien.</yellow>"
warning.config.number.binomial.missing_extra: "<yellow>Problème dans le fichier <arg:0> - La configuration '<arg:1>' na pas largument requis 'extra' pour un nombre binomial.</yellow>"
warning.config.number.binomial.missing_probability: "<yellow>Problème dans le fichier <arg:0> - La configuration '<arg:1>' na pas largument requis 'probability' pour un nombre binomial.</yellow>"
warning.config.condition.all_of.missing_terms: "<yellow>Problème dans le fichier <arg:0> - La configuration '<arg:1>' na pas largument requis 'terms' pour la condition 'all_of'.</yellow>"
warning.config.condition.all_of.invalid_terms_type: "<yellow>Problème dans le fichier <arg:0> - La condition 'all_of' de '<arg:1>' est mal configurée : 'terms' doit être une liste de maps, type actuel : '<arg:2>'.</yellow>"
warning.config.condition.any_of.missing_terms: "<yellow>Problème dans le fichier <arg:0> - La configuration '<arg:1>' na pas largument requis 'terms' pour la condition 'any_of'.</yellow>"
warning.config.condition.any_of.invalid_terms_type: "<yellow>Problème dans le fichier <arg:0> - La condition 'any_of' de '<arg:1>' est mal configurée : 'terms' doit être une liste de maps, type actuel : '<arg:2>'.</yellow>"
warning.config.condition.inverted.missing_term: "<yellow>Problème dans le fichier <arg:0> - La configuration '<arg:1>' na pas largument requis 'term' pour la condition 'inverted'.</yellow>"
warning.config.condition.inverted.invalid_term_type: "<yellow>Problème dans le fichier <arg:0> - La condition 'inverted' de '<arg:1>' est mal configurée : 'term' doit être une section de configuration, type actuel : '<arg:2>'.</yellow>"
warning.config.condition.enchantment.missing_predicate: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument obligatoire 'predicate' pour la condition 'enchantment'.</yellow>"
warning.config.condition.enchantment.invalid_predicate: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' utilise un argument 'predicate' invalide pour l'enchantement '<arg:2>'.</yellow>"
warning.config.condition.match_block_property.missing_properties: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument obligatoire 'properties' pour la condition 'match_block_property'.</yellow>"
warning.config.condition.match_block.missing_id: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument obligatoire 'id' pour la condition 'match_block'.</yellow>"
warning.config.condition.match_entity.missing_id: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument obligatoire 'id' pour la condition 'match_entity'.</yellow>"
warning.config.condition.match_item.missing_id: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument obligatoire 'id' pour la condition 'match_item'.</yellow>"
warning.config.condition.table_bonus.missing_enchantment: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument obligatoire 'enchantment' pour la condition 'table_bonus'.</yellow>"
warning.config.condition.table_bonus.missing_chances: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument obligatoire 'chances' pour la condition 'table_bonus'.</yellow>"
warning.config.condition.permission.missing_permission: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument obligatoire 'permission' pour la condition 'permission'.</yellow>"
warning.config.condition.string_equals.missing_value1: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument obligatoire 'value1' pour la condition 'string_equals'.</yellow>"
warning.config.condition.string_equals.missing_value2: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument obligatoire 'value2' pour la condition 'string_equals'.</yellow>"
warning.config.condition.string_contains.missing_value1: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument obligatoire 'value1' pour la condition 'string_contains'.</yellow>"
warning.config.condition.string_contains.missing_value2: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument obligatoire 'value2' pour la condition 'string_contains'.</yellow>"
warning.config.condition.string_regex.missing_value: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument obligatoire 'value' pour la condition 'string_regex'.</yellow>"
warning.config.condition.string_regex.missing_regex: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument obligatoire 'regex' pour la condition 'string_regex'.</yellow>"
warning.config.condition.expression.missing_expression: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument obligatoire 'expression' pour la condition 'expression'.</yellow>"
warning.config.condition.is_null.missing_argument: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument obligatoire 'argument' pour la condition 'is_null'.</yellow>"
warning.config.condition.hand.missing_hand: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument obligatoire 'hand' pour la condition 'hand'.</yellow>"
warning.config.condition.hand.invalid_hand: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' utilise un argument 'hand' invalide '<arg:2>' pour la condition 'hand'. Types de main autorisés : [<arg:3>]</yellow>"
warning.config.condition.on_cooldown.missing_id: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument obligatoire 'id' pour la condition 'on_cooldown'.</yellow>"
warning.config.structure.not_section: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' est censée être une section, mais est de type '<arg:2>'.</yellow>"
warning.config.image.duplicate: "<yellow>Problème trouvé dans le fichier <arg:0> - Image dupliquée '<arg:1>'. Vérifiez sil y a la même configuration dans dautres fichiers.</yellow>"
warning.config.image.missing_height: "<yellow>Problème trouvé dans le fichier <arg:0> - Limage '<arg:1>' manque largument obligatoire 'height'.</yellow>"
warning.config.image.height_ascent_conflict: "<yellow>Problème trouvé dans le fichier <arg:0> - Limage '<arg:1>' viole la règle bitmap : 'height' '<arg:2>' ne doit pas être inférieur à 'ascent' '<arg:3>'.</yellow>"
warning.config.image.missing_file: "<yellow>Problème trouvé dans le fichier <arg:0> - Limage '<arg:1>' manque largument obligatoire 'file'.</yellow>"
warning.config.image.invalid_file_chars: "<yellow>Problème trouvé dans le fichier <arg:0> - Limage '<arg:1>' a un argument 'file' '<arg:2>' avec des caractères illégaux. Consultez https://minecraft.wiki/w/Resource_location#Legal_characters.</yellow>"
warning.config.image.invalid_font_chars: "<yellow>Problème trouvé dans le fichier <arg:0> - Limage '<arg:1>' a un argument 'font' '<arg:2>' avec des caractères illégaux. Consultez https://minecraft.wiki/w/Resource_location#Legal_characters.</yellow>"
warning.config.image.invalid_grid_size: "<yellow>Problème trouvé dans le fichier <arg:0> - Limage '<arg:1>' utilise un format de grille incorrect '<arg:2>'. Exemple correct : '3,5'</yellow>"
warning.config.image.missing_char: "<yellow>Problème trouvé dans le fichier <arg:0> - Limage '<arg:1>' manque largument obligatoire 'char'.</yellow>"
warning.config.image.codepoint.conflict: "<yellow>Problème trouvé dans le fichier <arg:0> - Limage '<arg:1>' utilise le caractère '<arg:3>(<arg:4>)' déjà utilisé par limage '<arg:5>' pour la police <arg:2>.</yellow>"
warning.config.image.codepoint.exhausted: "<yellow>Problème trouvé dans le fichier <arg:0> - Impossible dallouer un codepoint pour limage '<arg:1>' car tous les codepoints sont déjà utilisés pour la police '<arg:2>'.</yellow>"
warning.config.image.invalid_codepoint_grid: "<yellow>Problème trouvé dans le fichier <arg:0> - Limage '<arg:1>' a une grille de codepoints 'chars' invalide.</yellow>"
warning.config.image.invalid_char: "<yellow>Problème trouvé dans le fichier <arg:0> - Limage '<arg:1>' contient un caractère combiné, ce qui peut entraîner une séparation de limage.</yellow>"
warning.config.image.invalid_hex_value: "<yellow>Problème trouvé dans le fichier <arg:0> - Limage '<arg:1>' utilise le caractère unicode '<arg:2>' qui nest pas une valeur hexadécimale valide.</yellow>"
warning.config.image.invalid_unicode_string: "<yellow>Problème trouvé dans le fichier <arg:0> - Limage '<arg:1>' utilise une chaîne unicode incorrecte '<arg:2>'.</yellow>"
warning.config.recipe.duplicate: "<yellow>Problème trouvé dans le fichier <arg:0> - Recette dupliquée '<arg:1>'. Vérifiez sil y a la même configuration dans dautres fichiers.</yellow>"
warning.config.recipe.missing_type: "<yellow>Problème trouvé dans le fichier <arg:0> - La recette '<arg:1>' manque largument obligatoire 'type'.</yellow>"
warning.config.recipe.invalid_type: "<yellow>Problème trouvé dans le fichier <arg:0> - La recette '<arg:1>' utilise un type de recette invalide '<arg:2>'.</yellow>"
warning.config.recipe.invalid_ingredient: "<yellow>Problème trouvé dans le fichier <arg:0> - La recette '<arg:1>' utilise un ingrédient invalide '<arg:2>'.</yellow>"
warning.config.recipe.invalid_result: "<yellow>Problème trouvé dans le fichier <arg:0> - La recette '<arg:1>' utilise un résultat invalide '<arg:2>'.</yellow>"
warning.config.recipe.missing_ingredient: "<yellow>Problème trouvé dans le fichier <arg:0> - La recette de cuisson '<arg:1>' manque largument obligatoire 'ingredient'.</yellow>"
warning.config.recipe.missing_result: "<yellow>Problème trouvé dans le fichier <arg:0> - La recette '<arg:1>' manque largument obligatoire 'result'.</yellow>"
warning.config.recipe.result.missing_id: "<yellow>Problème trouvé dans le fichier <arg:0> - La recette '<arg:1>' manque largument obligatoire 'id' pour le résultat de la recette.</yellow>"
warning.config.recipe.crafting.invalid_category: "<yellow>Problème trouvé dans le fichier <arg:0> - La recette de crafting '<arg:1>' utilise une catégorie invalide '<arg:2>'. Catégories autorisées : [<arg:3>].</yellow>"
warning.config.recipe.cooking.invalid_category: "<yellow>Problème trouvé dans le fichier <arg:0> - La recette de cuisson '<arg:1>' utilise une catégorie invalide '<arg:2>'. Catégories autorisées : [<arg:3>].</yellow>"
warning.config.recipe.shaped.missing_pattern: "<yellow>Problème trouvé dans le fichier <arg:0> - La recette avec forme '<arg:1>' manque largument obligatoire 'pattern'.</yellow>"
warning.config.recipe.shaped.invalid_pattern: "<yellow>Problème trouvé dans le fichier <arg:0> - La recette avec forme '<arg:1>' utilise un motif invalide '<arg:2>'.</yellow>"
warning.config.recipe.shaped.invalid_symbol: "<yellow>Problème trouvé dans le fichier <arg:0> - La recette avec forme '<arg:1>' utilise un symbole invalide '<arg:2>' dans le motif.</yellow>"
warning.config.recipe.smithing_transform.post_processor.missing_type: "<yellow>Problème trouvé dans le fichier <arg:0> - La recette de transformation de forge '<arg:1>' manque largument obligatoire 'type' pour lun de ses post-processeurs.</yellow>"
warning.config.recipe.smithing_transform.post_processor.invalid_type: "<yellow>Problème trouvé dans le fichier <arg:0> - La recette de transformation de forge '<arg:1>' utilise un type de post-processeur invalide '<arg:2>'.</yellow>"
warning.config.recipe.smithing_transform.post_processor.keep_component.missing_components: "<yellow>Problème trouvé dans le fichier <arg:0> - La recette de transformation de forge '<arg:1>' manque largument obligatoire 'components' pour le post-processeur 'keep_components'.</yellow>"
warning.config.recipe.smithing_transform.post_processor.keep_component.missing_tags: "<yellow>Problème trouvé dans le fichier <arg:0> - La recette de transformation de forge '<arg:1>' manque largument obligatoire 'tags' pour le post-processeur 'keep_tags'.</yellow>"
warning.config.recipe.smithing_transform.missing_base: "<yellow>Problème trouvé dans le fichier <arg:0> - La recette de transformation de forge '<arg:1>' manque largument obligatoire 'base'.</yellow>"
warning.config.recipe.smithing_trim.missing_base: "<yellow>Problème trouvé dans le fichier <arg:0> - La recette de découpe de forge '<arg:1>' manque largument obligatoire 'base'.</yellow>"
warning.config.recipe.smithing_trim.missing_template_type: "<yellow>Problème trouvé dans le fichier <arg:0> - La recette de découpe de forge '<arg:1>' manque largument obligatoire 'template-type'.</yellow>"
warning.config.recipe.smithing_trim.missing_addition: "<yellow>Problème trouvé dans le fichier <arg:0> - La recette de découpe de forge '<arg:1>' manque largument obligatoire 'addition'.</yellow>"
warning.config.recipe.smithing_trim.missing_pattern: "<yellow>Problème trouvé dans le fichier <arg:0> - La recette de découpe de forge '<arg:1>' manque largument obligatoire 'pattern'.</yellow>"
warning.config.recipe.brewing.missing_container: "<yellow>Problème trouvé dans le fichier <arg:0> - La recette de brassage '<arg:1>' manque largument obligatoire 'container'.</yellow>"
warning.config.recipe.brewing.missing_ingredient: "<yellow>Problème trouvé dans le fichier <arg:0> - La recette de brassage '<arg:1>' manque largument obligatoire 'ingredient'.</yellow>"
warning.config.recipe.result.post_processor.missing_type: "<yellow>Problème trouvé dans le fichier <arg:0> - La recette '<arg:1>' manque largument obligatoire 'type' pour les post-processeurs de résultat.</yellow>"
warning.config.recipe.result.post_processor.invalid_type: "<yellow>Problème trouvé dans le fichier <arg:0> - La recette '<arg:1>' utilise un type de post-processeur de résultat invalide '<arg:2>'.</yellow>"
warning.config.translation.unknown_locale: "<yellow>Problème trouvé dans le fichier <arg:0> - Locale inconnue '<arg:1>'.</yellow>"
warning.config.template.duplicate: "<yellow>Problème trouvé dans le fichier <arg:0> - Modèle dupliqué '<arg:1>'. Vérifiez sil existe la même configuration dans dautres fichiers.</yellow>"
warning.config.template.invalid: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' utilise un modèle invalide '<arg:2>'.</yellow>"
warning.config.template.argument.self_increase_int.invalid_range: "<yellow>Problème trouvé dans le fichier <arg:0> - Le modèle '<arg:1>' utilise un 'from' '<arg:2>' supérieur à 'to' '<arg:3>' dans largument 'self_increase_int'.</yellow>"
warning.config.template.argument.list.invalid_type: "<yellow>Problème trouvé dans le fichier <arg:0> - Le modèle '<arg:1>' utilise un argument 'list' qui attend une 'List', mais le type fourni est '<arg:2>'.</yellow>"
warning.config.template.argument.missing_value: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque la valeur de largument de modèle '<arg:2>'. Utilisez loption 'arguments' pour définir une valeur par défaut.</yellow>"
warning.config.vanilla_loot.missing_type: "<yellow>Problème trouvé dans le fichier <arg:0> - Le loot vanilla '<arg:1>' manque largument obligatoire 'type'.</yellow>"
warning.config.vanilla_loot.invalid_type: "<yellow>Problème trouvé dans le fichier <arg:0> - Le loot vanilla '<arg:1>' utilise un type invalide '<arg:2>'. Types autorisés : [<arg:3>].</yellow>"
warning.config.vanilla_loot.block.invalid_target: "<yellow>Problème trouvé dans le fichier <arg:0> - Cible de bloc invalide '<arg:2>' dans le loot vanilla '<arg:1>'.</yellow>"
warning.config.sound.duplicate: "<yellow>Problème trouvé dans le fichier <arg:0> - Son dupliqué '<arg:1>'. Vérifiez sil existe la même configuration dans dautres fichiers.</yellow>"
warning.config.sound.missing_sounds: "<yellow>Problème trouvé dans le fichier <arg:0> - Le son '<arg:1>' manque largument obligatoire 'sounds'.</yellow>"
warning.config.sound.missing_name: "<yellow>Problème trouvé dans le fichier <arg:0> - Le son '<arg:1>' manque largument obligatoire 'name'.</yellow>"
warning.config.jukebox_song.duplicate: "<yellow>Problème trouvé dans le fichier <arg:0> - Chanson de jukebox dupliquée '<arg:1>'. Vérifiez sil existe la même configuration dans dautres fichiers.</yellow>"
warning.config.jukebox_song.missing_sound: "<yellow>Problème trouvé dans le fichier <arg:0> - La chanson de jukebox '<arg:1>' manque largument obligatoire 'sound'.</yellow>"
warning.config.furniture.duplicate: "<yellow>Problème trouvé dans le fichier <arg:0> - Meuble dupliqué '<arg:1>'. Vérifiez sil existe la même configuration dans dautres fichiers.</yellow>"
warning.config.furniture.missing_placement: "<yellow>Problème trouvé dans le fichier <arg:0> - Le meuble '<arg:1>' manque largument obligatoire 'placement'.</yellow>"
warning.config.furniture.element.missing_item: "<yellow>Problème trouvé dans le fichier <arg:0> - Le meuble '<arg:1>' manque largument obligatoire 'item' pour un de ses éléments.</yellow>"
warning.config.furniture.settings.unknown: "<yellow>Problème trouvé dans le fichier <arg:0> - Le meuble '<arg:1>' utilise un type de paramètre inconnu '<arg:2>'.</yellow>"
warning.config.furniture.hitbox.invalid_type: "<yellow>Problème trouvé dans le fichier <arg:0> - Le meuble '<arg:1>' utilise un type de hitbox invalide '<arg:2>'.</yellow>"
warning.config.furniture.hitbox.custom.invalid_entity: "<yellow>Problème trouvé dans le fichier <arg:0> - Le meuble '<arg:1>' utilise un hitbox personnalisé avec un type dentité invalide '<arg:2>'.</yellow>"
warning.config.item.duplicate: "<yellow>Problème trouvé dans le fichier <arg:0> - Objet dupliqué '<arg:1>'. Vérifiez sil existe la même configuration dans dautres fichiers.</yellow>"
warning.config.item.settings.unknown: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' utilise un type de paramètre inconnu '<arg:2>'.</yellow>"
warning.config.item.settings.invulnerable.invalid_damage_source: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' utilise une source de dégâts inconnue '<arg:2>'. Sources autorisées : [<arg:3>].</yellow>"
warning.config.item.settings.equipment.missing_asset_id: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument obligatoire 'asset-id' pour le paramètre 'equipment'.</yellow>"
warning.config.item.settings.equipment.invalid_asset_id: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' utilise un 'asset-id' invalide pour le paramètre 'equipment'. Il se peut que la configuration de léquipement nexiste pas ou que lID soit mal orthographié.</yellow>"
warning.config.item.settings.projectile.missing_item: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument obligatoire 'item' pour le paramètre 'projectile'.</yellow>"
warning.config.item.settings.craft_remainder.missing_type: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument obligatoire 'type' pour 'craft-remainder'.</yellow>"
warning.config.item.settings.craft_remainder.invalid_type: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' utilise un type de 'craft-remainder' invalide '<arg:2>'.</yellow>"
warning.config.item.settings.craft_remainder.fixed.missing_item: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument obligatoire 'item' pour un 'craft-remainder' fixe.</yellow>"
warning.config.item.settings.craft_remainder.recipe_based.missing_terms: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument obligatoire 'terms' pour un 'craft-remainder' basé sur une recette.</yellow>"
warning.config.item.data.attribute_modifiers.missing_type: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument obligatoire 'type' pour les données 'attribute-modifiers'.</yellow>"
warning.config.item.data.attribute_modifiers.missing_amount: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument obligatoire 'amount' pour les données 'attribute-modifiers'.</yellow>"
warning.config.item.data.attribute_modifiers.missing_operation: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument obligatoire 'operation' pour les données 'attribute-modifiers'.</yellow>"
warning.config.item.data.attribute_modifiers.display.missing_type: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument obligatoire 'type' pour les données daffichage 'attribute-modifiers'.</yellow>"
warning.config.item.data.attribute_modifiers.display.missing_value: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument obligatoire 'value' pour les données daffichage 'attribute-modifiers'.</yellow>"
warning.config.item.data.external.missing_source: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument obligatoire 'source' pour les données 'external'.</yellow>"
warning.config.item.data.external.missing_id: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument obligatoire 'id' pour les données 'external'.</yellow>"
warning.config.item.data.external.invalid_source: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' utilise une source de données 'external' invalide '<arg:2>'.</yellow>"
warning.config.item.missing_material: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument obligatoire 'material'.</yellow>"
warning.config.item.invalid_material: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' utilise un type de matériau invalide '<arg:2>'.</yellow>"
warning.config.item.invalid_custom_model_data: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' utilise des données de modèle personnalisées négatives '<arg:2>', ce qui est invalide.</yellow>"
warning.config.item.bad_custom_model_data: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' utilise des données de modèle personnalisées trop grandes '<arg:2>'. Il est recommandé dutiliser une valeur inférieure à 16 777 216.</yellow>"
warning.config.item.item_model.conflict: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' utilise une option 'item-model' invalide car ce modèle est déjà utilisé par un objet vanilla.</yellow>"
warning.config.item.custom_model_data.conflict: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' utilise des données de modèle personnalisées '<arg:2>' déjà attribuées à lobjet '<arg:3>'.</yellow>"
warning.config.item.custom_model_data.exhausted: "<yellow>Problème trouvé dans le fichier <arg:0> - Impossible dallouer des données de modèle personnalisées pour lobjet '<arg:1>' car toutes les données disponibles pour le matériau '<arg:2>' sont épuisées.</yellow>"
warning.config.item.invalid_component: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' utilise un type de composant inexistant '<arg:2>'.</yellow>"
warning.config.item.missing_model_id: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'custom-model-data' ou 'item-model'.</yellow>"
warning.config.item.missing_model: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque la section 'model' requise pour la compatibilité avec les packs de ressources 1.21.4+.</yellow>"
warning.config.item.behavior.missing_type: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'type' pour son comportement.</yellow>"
warning.config.item.behavior.invalid_type: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' utilise un type de comportement invalide '<arg:2>'.</yellow>"
warning.config.item.behavior.block.missing_block: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'block' pour le comportement 'block_item'.</yellow>"
warning.config.item.behavior.wall_block.missing_block: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'block' pour le comportement 'wall_block_item'.</yellow>"
warning.config.item.behavior.furniture.missing_furniture: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'furniture' pour le comportement 'furniture_item'.</yellow>"
warning.config.item.behavior.liquid_collision.missing_block: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'block' pour le comportement 'liquid_collision_block_item'.</yellow>"
warning.config.item.behavior.double_high.missing_block: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'block' pour le comportement 'double_high_block_item'.</yellow>"
warning.config.item.legacy_model.missing_path: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'path' pour le modèle legacy.</yellow>"
warning.config.item.legacy_model.overrides.missing_path: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'path' pour les overrides du modèle legacy.</yellow>"
warning.config.item.legacy_model.overrides.missing_predicate: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'predicate' pour les overrides du modèle legacy.</yellow>"
warning.config.item.legacy_model.cannot_convert: "<yellow>Problème trouvé dans le fichier <arg:0> - Impossible de convertir les objets 1.21.4+ au format legacy pour lobjet '<arg:1>'. Veuillez créer manuellement la section 'legacy-model'.</yellow>"
warning.config.item.model.invalid_type: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' utilise un type de modèle invalide '<arg:2>'.</yellow>"
warning.config.item.model.tint.missing_type: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'type' pour le tint.</yellow>"
warning.config.item.model.tint.invalid_type: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' utilise un type de tint invalide '<arg:2>'.</yellow>"
warning.config.item.model.tint.constant.missing_value: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'value' pour le tint constant.</yellow>"
warning.config.item.model.tint.grass.invalid_temp: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' utilise une température invalide '<arg:2>' pour le tint de lherbe (valeurs attendues entre 0 et 1).</yellow>"
warning.config.item.model.tint.grass.invalid_downfall: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' utilise une précipitation invalide '<arg:2>' pour le tint de lherbe (valeurs attendues entre 0 et 1).</yellow>"
warning.config.item.model.tint.invalid_value: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' utilise un tint invalide '<arg:2>'.</yellow>"
warning.config.item.model.base.missing_path: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'path' pour le modèle 'minecraft:model'.</yellow>"
warning.config.item.model.base.invalid_path: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' a un 'path' invalide '<arg:2>' contenant des caractères interdits. Voir https://minecraft.wiki/w/Resource_location#Legal_characters.</yellow>"
warning.config.item.model.condition.missing_property: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'property' pour le modèle 'minecraft:condition'.</yellow>"
warning.config.item.model.condition.invalid_property: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' utilise une propriété invalide '<arg:2>' pour le modèle 'minecraft:condition'.</yellow>"
warning.config.item.model.condition.missing_on_true: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'on-true' pour le modèle 'minecraft:condition'.</yellow>"
warning.config.item.model.condition.missing_on_false: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'on-false' pour le modèle 'minecraft:condition'.</yellow>"
warning.config.item.model.condition.keybind.missing_keybind: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'keybind' pour la propriété 'minecraft:keybind_down'.</yellow>"
warning.config.item.model.condition.has_component.missing_component: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'component' pour la propriété 'minecraft:has_component'.</yellow>"
warning.config.item.model.condition.component.missing_predicate: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'predicate' pour la propriété 'minecraft:component'.</yellow>"
warning.config.item.model.condition.component.missing_value: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'value' pour la propriété 'minecraft:component'.</yellow>"
warning.config.item.model.composite.missing_models: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'models' pour le modèle 'minecraft:composite'.</yellow>"
warning.config.item.model.range_dispatch.missing_property: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'property' pour le modèle 'minecraft:range_dispatch'.</yellow>"
warning.config.item.model.range_dispatch.invalid_property: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' utilise une propriété invalide '<arg:2>' pour le modèle 'minecraft:range_dispatch'.</yellow>"
warning.config.item.model.range_dispatch.missing_entries: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'entries' pour le modèle 'minecraft:composite'.</yellow>"
warning.config.item.model.range_dispatch.entry.missing_model: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'model' pour lune des entrées du modèle 'minecraft:composite'.</yellow>"
warning.config.item.model.range_dispatch.compass.missing_target: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'target' pour la propriété 'minecraft:compass'.</yellow>"
warning.config.item.model.range_dispatch.time.missing_source: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'source' pour la propriété 'minecraft:time'.</yellow>"
warning.config.item.model.select.missing_property: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'property' pour le modèle 'minecraft:select'.</yellow>"
warning.config.item.model.select.invalid_property: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' utilise une propriété invalide '<arg:2>' pour le modèle 'minecraft:select'.</yellow>"
warning.config.item.model.select.missing_cases: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'cases' pour le modèle 'minecraft:select'.</yellow>"
warning.config.item.model.select.case.missing_when: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'when' pour lun des cas du modèle 'minecraft:select'.</yellow>"
warning.config.item.model.select.case.missing_model: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'model' pour lun des cas du modèle 'minecraft:select'.</yellow>"
warning.config.item.model.select.block_state.missing_property: "<yellow>Problème trouvé dans le fichier <arg:0> - Lobjet '<arg:1>' manque largument requis 'block-state-property' pour la propriété 'minecraft:block_state'.</yellow>"
warning.config.item.model.select.local_time.missing_pattern: "<yellow>Problème trouvé dans le fichier <arg:0> - L'objet '<arg:1>' manque l'argument requis 'pattern' pour la propriété 'minecraft:local_time'.</yellow>"
warning.config.item.model.select.component.missing_component: "<yellow>Problème trouvé dans le fichier <arg:0> - L'objet '<arg:1>' manque l'argument requis 'component' pour la propriété 'minecraft:component'.</yellow>"
warning.config.item.model.special.missing_type: "<yellow>Problème trouvé dans le fichier <arg:0> - L'objet '<arg:1>' manque l'argument requis 'type' pour le modèle 'minecraft:special'.</yellow>"
warning.config.item.model.special.missing_path: "<yellow>Problème trouvé dans le fichier <arg:0> - L'objet '<arg:1>' manque l'argument requis 'path' pour le modèle 'minecraft:special'.</yellow>"
warning.config.item.model.special.invalid_path: "<yellow>Problème trouvé dans le fichier <arg:0> - L'objet '<arg:1>' utilise un argument 'path' invalide '<arg:2>' pour le modèle 'minecraft:special' contenant des caractères interdits. Veuillez lire https://minecraft.wiki/w/Resource_location#Legal_characters.</yellow>"
warning.config.item.model.special.invalid_type: "<yellow>Problème trouvé dans le fichier <arg:0> - L'objet '<arg:1>' utilise un type invalide '<arg:2>' pour le modèle 'minecraft:special'.</yellow>"
warning.config.item.model.special.banner.missing_color: "<yellow>Problème trouvé dans le fichier <arg:0> - L'objet '<arg:1>' manque l'argument requis 'color' pour le modèle spécial 'minecraft:banner'.</yellow>"
warning.config.item.model.special.bed.missing_texture: "<yellow>Problème trouvé dans le fichier <arg:0> - L'objet '<arg:1>' manque l'argument requis 'texture' pour le modèle spécial 'minecraft:bed'.</yellow>"
warning.config.item.model.special.sign.missing_wood_type: "<yellow>Problème trouvé dans le fichier <arg:0> - L'objet '<arg:1>' manque l'argument requis 'wood-type' pour le modèle spécial 'minecraft:hanging_sign'/'minecraft:standing_sign'.</yellow>"
warning.config.item.model.special.sign.missing_texture: "<yellow>Problème trouvé dans le fichier <arg:0> - L'objet '<arg:1>' manque l'argument requis 'texture' pour le modèle spécial 'minecraft:hanging_sign'/'minecraft:standing_sign'.</yellow>"
warning.config.item.model.special.chest.missing_texture: "<yellow>Problème trouvé dans le fichier <arg:0> - L'objet '<arg:1>' manque l'argument requis 'texture' pour le modèle spécial 'minecraft:chest'.</yellow>"
warning.config.item.model.special.chest.invalid_openness: "<yellow>Problème trouvé dans le fichier <arg:0> - L'objet '<arg:1>' utilise une valeur 'openness' invalide '<arg:2>' pour le modèle spécial 'minecraft:chest'. Plage valide '0~1'.</yellow>"
warning.config.item.model.special.shulker_box.missing_texture: "<yellow>Problème trouvé dans le fichier <arg:0> - L'objet '<arg:1>' manque l'argument requis 'texture' pour le modèle spécial 'minecraft:shulker_box'.</yellow>"
warning.config.item.model.special.shulker_box.invalid_openness: "<yellow>Problème trouvé dans le fichier <arg:0> - L'objet '<arg:1>' utilise une valeur 'openness' invalide '<arg:2>' pour le modèle spécial 'minecraft:shulker_box'. Plage valide '0~1'.</yellow>"
warning.config.item.model.special.head.missing_kind: "<yellow>Problème trouvé dans le fichier <arg:0> - L'objet '<arg:1>' manque l'argument requis 'kind' pour le modèle spécial 'minecraft:head'.</yellow>"
warning.config.item.model.special.copper_golem_statue.missing_pose: "<yellow>Problème trouvé dans le fichier <arg:0> - L'objet '<arg:1>' manque l'argument requis 'pose' pour le modèle spécial 'minecraft:copper_golem_statue'.</yellow>"
warning.config.item.model.special.copper_golem_statue.missing_texture: "<yellow>Problème trouvé dans le fichier <arg:0> - L'objet '<arg:1>' manque l'argument requis 'texture' pour le modèle spécial 'minecraft:copper_golem_statue'.</yellow>"
warning.config.item.updater.missing_type: "<yellow>Problème trouvé dans le fichier <arg:0> - L'objet '<arg:1>' manque l'argument requis 'type' pour le mise à jour d'objet.</yellow>"
warning.config.item.updater.invalid_type: "<yellow>Problème trouvé dans le fichier <arg:0> - L'objet '<arg:1>' utilise un argument 'type' invalide '<arg:2>' pour le mise à jour d'objet.</yellow>"
warning.config.item.updater.transmute.missing_material: "<yellow>Problème trouvé dans le fichier <arg:0> - L'objet '<arg:1>' manque l'argument requis 'material' pour la mise à jour d'objet 'transmute'.</yellow>"
warning.config.block_state_mapping.invalid_state: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' utilise un état de bloc invalide '<arg:2>'.</yellow>"
warning.config.block_state_mapping.conflict: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' ne peut pas mapper l'état de bloc <arg:2> à <arg:3> car il a déjà été mappé à <arg:4>.</yellow>"
warning.config.block.duplicate: "<yellow>Problème trouvé dans le fichier <arg:0> - Bloc dupliqué '<arg:1>'. Vérifiez si la même configuration existe dans d'autres fichiers.</yellow>"
warning.config.block.missing_state: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque l'argument requis 'state'.</yellow>"
warning.config.block.state.property.missing_type: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque l'argument requis 'type' pour la propriété '<arg:2>'.</yellow>"
warning.config.block.state.property.invalid_type: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' utilise un argument 'type' invalide '<arg:2>' pour la propriété '<arg:3>'.</yellow>"
warning.config.block.state.property.integer.invalid_range: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' utilise un argument 'range' invalide '<arg:2>' pour la propriété entière '<arg:3>'. Syntaxe correcte: 1~2.</yellow>"
warning.config.block.state.property.invalid_format: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' utilise un format de propriété d'état de bloc invalide '<arg:2>'.</yellow>"
warning.config.block.state.missing_state: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque l'argument requis 'state' pour 'state'.</yellow>"
warning.config.block.state.missing_properties: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque la section requise 'properties' pour 'states'.</yellow>"
warning.config.block.state.missing_appearances: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque la section requise 'appearances' pour 'states'.</yellow>"
warning.config.block.state.entity_renderer.invalid_type: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' utilise un type de renderer d'entité invalide '<arg:2>'.</yellow>"
warning.config.block.state.entity_renderer.item_display.missing_item: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque l'argument requis 'item' pour le renderer d'entité 'item_display'.</yellow>"
warning.config.block.state.entity_renderer.text_display.missing_text: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque l'argument requis 'text' pour le renderer d'entité 'text_display'.</yellow>"
warning.config.block.state.entity_renderer.better_model.missing_model: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque l'argument requis 'model' pour le renderer d'entité 'better_model'.</yellow>"
warning.config.block.state.entity_renderer.model_engine.missing_model: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque l'argument requis 'model' pour le renderer d'entité 'model_engine'.</yellow>"
warning.config.block.state.variant.invalid_appearance: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' a une erreur: la variante '<arg:2>' utilise une apparence inexistante '<arg:3>'.</yellow>"
warning.config.block.state.invalid_vanilla: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' utilise un état de bloc vanilla invalide '<arg:2>'.</yellow>"
warning.config.block.state.invalid_auto_state: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' utilise un auto-état invalide '<arg:2>'. Valeurs autorisées: [<arg:3>].</yellow>"
warning.config.block.state.auto_state.exhausted: "<yellow>Problème trouvé dans le fichier <arg:0> - Le groupe d'état visuel '<arg:2>' a atteint sa capacité maximale de '<arg:3>' slots et ne peut pas allouer d'état pour le bloc '<arg:1>'.</yellow>"
warning.config.block.state.unavailable_vanilla: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' utilise un état de bloc vanilla non disponible '<arg:2>'. Veuillez libérer cet état dans block-state-mappings.</yellow>"
warning.config.block.state.invalid_vanilla_id: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' utilise un état de bloc vanilla '<arg:2>' qui dépasse la plage de slots disponible '0~<arg:3>'.</yellow>"
warning.config.block.state.invalid_id: "<yellow>Problème trouvé dans le fichier <arg:0> - La plage ID de l'état de bloc (<arg:2>) utilisée par le bloc '<arg:1>' est hors de la plage valide 0 à <arg:3>. Veuillez ajouter plus de blocs côté serveur dans 'config.yml' si les slots actuels sont épuisés.</yellow>"
warning.config.block.state.id.conflict: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' n'a pas pu lier l'état réel pour '<arg:2>' car il est occupé par '<arg:3>'.</yellow>"
warning.config.block.state.id.exhausted: "<yellow>Problème trouvé dans le fichier <arg:0> - Impossible d'allouer suffisamment d'état réel pour le bloc '<arg:1>'. Ajoutez plus de blocs côté serveur dans 'config.yml' et redémarrez si les slots actuels sont épuisés.</yellow>"
warning.config.block.state.model.missing_path: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque l'option requise 'path' pour 'model'.</yellow>"
warning.config.block.state.model.invalid_path: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' a un argument 'path' '<arg:2>' contenant des caractères interdits. Veuillez lire https://minecraft.wiki/w/Resource_location#Legal_characters</yellow>"
warning.config.block.state.model.conflict: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' essaie de lier le modèle '<arg:2>' à l'état '<arg:3>' déjà lié au modèle '<arg:4>'.</yellow>"
warning.config.block.settings.unknown: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' utilise un type de configuration inconnu '<arg:2>'.</yellow>"
warning.config.block.behavior.missing_type: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque l'argument requis 'type' pour le comportement du bloc.</yellow>"
warning.config.block.behavior.concrete.missing_solid: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de l'option requise 'solid-block' pour le comportement 'concrete_block'.</yellow>"
warning.config.block.behavior.crop.missing_age: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'age' pour le comportement 'crop_block'.</yellow>"
warning.config.block.behavior.vertical_crop.missing_age: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'age' pour le comportement 'vertical_crop_block'.</yellow>"
warning.config.block.behavior.leaves.missing_persistent: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'persistent' pour le comportement 'leaves_block'.</yellow>"
warning.config.block.behavior.leaves.missing_distance: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'distance' pour le comportement 'leaves_block'.</yellow>"
warning.config.block.behavior.lamp.missing_lit: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'lit' pour le comportement 'lamp_block'.</yellow>"
warning.config.block.behavior.toggleable_lamp.missing_lit: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'lit' pour le comportement 'toggleable_lamp_block'.</yellow>"
warning.config.block.behavior.toggleable_lamp.missing_powered: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'powered' pour le comportement 'toggleable_lamp_block'.</yellow>"
warning.config.block.behavior.door.missing_half: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'half' pour le comportement 'door_block'.</yellow>"
warning.config.block.behavior.door.missing_facing: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'facing' pour le comportement 'door_block'.</yellow>"
warning.config.block.behavior.door.missing_hinge: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'hinge' pour le comportement 'door_block'.</yellow>"
warning.config.block.behavior.door.missing_open: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'open' pour le comportement 'door_block'.</yellow>"
warning.config.block.behavior.door.missing_powered: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'powered' pour le comportement 'door_block'.</yellow>"
warning.config.block.behavior.trapdoor.missing_half: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'half' pour le comportement 'trapdoor_block'.</yellow>"
warning.config.block.behavior.trapdoor.missing_facing: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'facing' pour le comportement 'trapdoor_block'.</yellow>"
warning.config.block.behavior.trapdoor.missing_open: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'open' pour le comportement 'trapdoor_block'.</yellow>"
warning.config.block.behavior.trapdoor.missing_powered: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'powered' pour le comportement 'trapdoor_block'.</yellow>"
warning.config.block.behavior.stackable.missing_property: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise '<arg:2>' pour le comportement 'stackable_block'.</yellow>"
warning.config.block.behavior.stackable.missing_items: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de l'argument requis 'items' pour le comportement 'stackable_block'.</yellow>"
warning.config.block.behavior.fence_gate.missing_facing: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'facing' pour le comportement 'fence_gate_block'.</yellow>"
warning.config.block.behavior.fence_gate.missing_in_wall: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'in_wall' pour le comportement 'fence_gate_block'.</yellow>"
warning.config.block.behavior.fence_gate.missing_open: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'open' pour le comportement 'fence_gate_block'.</yellow>"
warning.config.block.behavior.fence_gate.missing_powered: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'powered' pour le comportement 'fence_gate_block'.</yellow>"
warning.config.block.behavior.slab.missing_type: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'type' pour le comportement 'slab_block'.</yellow>"
warning.config.block.behavior.stairs.missing_facing: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'facing' pour le comportement 'stairs_block'.</yellow>"
warning.config.block.behavior.stairs.missing_half: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'half' pour le comportement 'stairs_block'.</yellow>"
warning.config.block.behavior.stairs.missing_shape: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'shape' pour le comportement 'stairs_block'.</yellow>"
warning.config.block.behavior.sofa.missing_facing: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'facing' pour le comportement 'sofa_block'.</yellow>"
warning.config.block.behavior.sofa.missing_shape: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'shape' pour le comportement 'sofa_block'.</yellow>"
warning.config.block.behavior.pressure_plate.missing_powered: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'powered' pour le comportement 'pressure_plate_block'.</yellow>"
warning.config.block.behavior.grass.missing_feature: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de l'argument requis 'feature' pour le comportement 'grass_block'.</yellow>"
warning.config.block.behavior.double_high.missing_half: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'half' pour le comportement 'double_block'.</yellow>"
warning.config.block.behavior.change_over_time.missing_next_block: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de l'argument requis 'next_block' pour le comportement 'change_over_time_block'.</yellow>"
warning.config.block.behavior.directional_attached.missing_facing: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'facing' pour le comportement 'directional_attached_block'.</yellow>"
warning.config.block.behavior.wall_torch_particle.missing_facing: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'facing' pour le comportement 'wall_torch_particle_block'.</yellow>"
warning.config.block.behavior.fence.missing_north: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'north' pour le comportement 'fence_block'.</yellow>"
warning.config.block.behavior.fence.missing_east: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'east' pour le comportement 'fence_block'.</yellow>"
warning.config.block.behavior.fence.missing_south: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'south' pour le comportement 'fence_block'.</yellow>"
warning.config.block.behavior.fence.missing_west: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'west' pour le comportement 'fence_block'.</yellow>"
warning.config.block.behavior.face_attached_horizontal_directional.missing_face: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'face' pour le comportement 'face_attached_horizontal_directional_block'.</yellow>"
warning.config.block.behavior.face_attached_horizontal_directional.missing_facing: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'facing' pour le comportement 'face_attached_horizontal_directional_block'.</yellow>"
warning.config.block.behavior.button.missing_powered: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'powered' pour le comportement 'button_block'.</yellow>"
warning.config.block.behavior.stem.missing_age: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'age' pour le comportement 'stem_block'.</yellow>"
warning.config.block.behavior.stem.missing_fruit: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de l'argument requis 'fruit' pour le comportement 'stem_block'.</yellow>"
warning.config.block.behavior.stem.missing_attached_stem: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de l'argument requis 'attached_stem' pour le comportement 'stem_block'.</yellow>"
warning.config.block.behavior.attached_stem.missing_facing: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'facing' pour le comportement 'attached_stem_block'.</yellow>"
warning.config.block.behavior.attached_stem.missing_fruit: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de l'argument requis 'fruit' pour le comportement 'attached_stem_block'.</yellow>"
warning.config.block.behavior.attached_stem.missing_stem: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de l'argument requis 'stem' pour le comportement 'attached_stem_block'.</yellow>"
warning.config.block.behavior.chime.missing_sounds_projectile_hit: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de l'argument requis 'sounds.projectile-hit' pour le comportement 'chime_block'.</yellow>"
warning.config.block.behavior.surface_spreading.missing_base_block: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de l'argument requis 'base-block' pour le comportement 'surface_spreading_block'.</yellow>"
warning.config.block.behavior.snowy.missing_snowy: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'snowy' pour le comportement 'snowy_block'.</yellow>"
warning.config.block.behavior.sapling.missing_stage: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de la propriété requise 'stage' pour le comportement 'sapling_block'.</yellow>"
warning.config.block.behavior.sapling.missing_feature: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de l'argument requis 'feature' pour le comportement 'sapling_block'.</yellow>"
warning.config.block.behavior.strippable.missing_stripped: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' manque de l'argument requis 'stripped' pour le comportement 'strippable_block'.</yellow>"
warning.config.block.behavior.invalid_type: "<yellow>Problème trouvé dans le fichier <arg:0> - Le bloc '<arg:1>' utilise un type de comportement de bloc invalide '<arg:2>'.</yellow>"
warning.config.model.generation.missing_parent: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque de l'argument requis 'parent' dans la section 'generation'.</yellow>"
warning.config.model.generation.conflict: "<yellow>Problème trouvé dans le fichier <arg:0> - Impossible de générer le modèle pour '<arg:1>' car deux configurations ou plus essaient de générer des modèles JSON différents avec le même chemin : '<arg:2>'.</yellow>"
warning.config.model.generation.invalid_display_position: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' utilise une position d'affichage invalide '<arg:2>' dans la section 'generation.display'. Positions autorisées : [<arg:3>]</yellow>"
warning.config.model.generation.invalid_gui_light: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' utilise une option gui-light invalide '<arg:2>' dans la section 'generation'. Options autorisées : [<arg:3>]</yellow>"
warning.config.model.generation.texture.invalid: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' a une texture '<arg:2>' avec le chemin '<arg:3>' contenant des caractères interdits. Veuillez lire https://minecraft.wiki/w/Resource_location#Legal_characters.</yellow>"
warning.config.model.generation.parent.invalid: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' a un argument parent '<arg:2>' contenant des caractères interdits. Veuillez lire https://minecraft.wiki/w/Resource_location#Legal_characters.</yellow>"
warning.config.emoji.missing_keywords: "<yellow>Problème trouvé dans le fichier <arg:0> - L'emoji '<arg:1>' manque de l'argument requis 'keywords'.</yellow>"
warning.config.emoji.duplicate: "<yellow>Problème trouvé dans le fichier <arg:0> - Emoji dupliqué '<arg:1>'. Vérifiez si la même configuration existe dans d'autres fichiers.</yellow>"
warning.config.emoji.invalid_image: "<yellow>Problème trouvé dans le fichier <arg:0> - L'emoji '<arg:1>' utilise un argument 'image' invalide '<arg:2>'.</yellow>"
warning.config.advancement.duplicate: "<yellow>Problème trouvé dans le fichier <arg:0> - Avancement dupliqué '<arg:1>'. Vérifiez si la même configuration existe dans d'autres fichiers.</yellow>"
warning.config.loot_table.missing_pools: "<yellow>Problème trouvé dans le fichier <arg:0> - '<arg:1>' a une table de butin mal configurée qui manque de l'argument requis 'pools'.</yellow>"
warning.config.loot_table.invalid_pools_type: "<yellow>Problème trouvé dans le fichier <arg:0> - '<arg:1>' a une table de butin mal configurée, 'pools' doit être une liste de maps/arrays, type actuel : '<arg:2>'.</yellow>"
warning.config.loot_table.invalid_conditions_type: "<yellow>Problème trouvé dans le fichier <arg:0> - '<arg:1>' a une table de butin mal configurée, 'conditions' doit être une liste de maps, type actuel : '<arg:2>'.</yellow>"
warning.config.loot_table.invalid_functions_type: "<yellow>Problème trouvé dans le fichier <arg:0> - '<arg:1>' a une table de butin mal configurée, 'functions' doit être une liste de maps, type actuel : '<arg:2>'.</yellow>"
warning.config.loot_table.invalid_entries_type: "<yellow>Problème trouvé dans le fichier <arg:0> - '<arg:1>' a une table de butin mal configurée, 'entries' doit être une liste de maps, type actuel : '<arg:2>'.</yellow>"
warning.config.loot_table.function.missing_type: "<yellow>Problème trouvé dans le fichier <arg:0> - '<arg:1>' a une table de butin mal configurée, une des fonctions manque de l'argument requis 'type'.</yellow>"
warning.config.loot_table.function.invalid_type: "<yellow>Problème trouvé dans le fichier <arg:0> - '<arg:1>' a une table de butin mal configurée, une des fonctions utilise un type de fonction invalide '<arg:2>'.</yellow>"
warning.config.loot_table.function.apply_bonus.missing_enchantment: "<yellow>Problème trouvé dans le fichier <arg:0> - '<arg:1>' a une table de butin mal configurée, la fonction 'apply_bonus' manque de l'argument requis 'enchantment'.</yellow>"
warning.config.loot_table.function.apply_bonus.missing_formula: "<yellow>Problème trouvé dans le fichier <arg:0> - '<arg:1>' a une table de butin mal configurée, la fonction 'apply_bonus' manque de l'argument requis 'formula'.</yellow>"
warning.config.loot_table.function.drop_exp.missing_count: "<yellow>Problème trouvé dans le fichier <arg:0> - '<arg:1>' a une table de butin mal configurée, la fonction 'drop_exp' manque de l'argument requis 'count'.</yellow>"
warning.config.loot_table.function.set_count.missing_count: "<yellow>Problème trouvé dans le fichier <arg:0> - '<arg:1>' a une table de butin mal configurée, la fonction 'set_count' manque de l'argument requis 'count'.</yellow>"
warning.config.loot_table.function.apply_data.missing_data: "<yellow>Problème trouvé dans le fichier <arg:0> - '<arg:1>' a une table de butin mal configurée, la fonction 'apply_data' manque de l'argument requis 'data'.</yellow>"
warning.config.loot_table.entry.missing_type: "<yellow>Problème trouvé dans le fichier <arg:0> - '<arg:1>' a une table de butin mal configurée, une des entrées manque de l'argument requis 'type'.</yellow>"
warning.config.loot_table.entry.invalid_type: "<yellow>Problème trouvé dans le fichier <arg:0> - '<arg:1>' a une table de butin mal configurée, une des entrées utilise un type invalide '<arg:2>'.</yellow>"
warning.config.loot_table.entry.exp.missing_count: "<yellow>Problème trouvé dans le fichier <arg:0> - '<arg:1>' a une table de butin mal configurée, l'entrée 'exp' manque de l'argument requis 'count'.</yellow>"
warning.config.loot_table.entry.item.missing_item: "<yellow>Problème trouvé dans le fichier <arg:0> - '<arg:1>' a une table de butin mal configurée, l'entrée 'item' manque de l'argument requis 'item'.</yellow>"
warning.config.loot_table.condition.missing_type: "<yellow>Problème trouvé dans le fichier <arg:0> - '<arg:1>' a une table de butin mal configurée, une des conditions manque de l'argument requis 'type'.</yellow>"
warning.config.loot_table.condition.invalid_type: "<yellow>Problème trouvé dans le fichier <arg:0> - '<arg:1>' a une table de butin mal configurée, une des conditions utilise un type invalide '<arg:2>'.</yellow>"
warning.config.host.missing_type: "<yellow>Problème trouvé dans config.yml à 'resource-pack.delivery.hosting' - L'argument requis 'type' est manquant pour l'hôte.</yellow>"
warning.config.host.invalid_type: "<yellow>Problème trouvé dans config.yml à 'resource-pack.delivery.hosting' - Le type d'hôte '<arg:0>' est invalide. Veuillez lire https://xiao-momi.github.io/craft-engine-wiki/getting_start/set_up_host</yellow>"
warning.config.host.external.missing_url: "<yellow>Problème trouvé dans config.yml à 'resource-pack.delivery.hosting' - L'argument requis 'url' est manquant pour l'hôte externe.</yellow>"
warning.config.host.alist.missing_api_url: "<yellow>Problème trouvé dans config.yml à 'resource-pack.delivery.hosting' - L'argument requis 'api-url' est manquant pour l'hôte alist.</yellow>"
warning.config.host.alist.missing_username: "<yellow>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.</yellow>"
warning.config.host.alist.missing_password: "<yellow>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.</yellow>"
warning.config.host.alist.missing_upload_path: "<yellow>Problème trouvé dans config.yml à 'resource-pack.delivery.hosting' - L'argument requis 'upload-path' est manquant pour l'hôte alist.</yellow>"
warning.config.host.dropbox.missing_app_key: "<yellow>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.</yellow>"
warning.config.host.dropbox.missing_app_secret: "<yellow>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.</yellow>"
warning.config.host.dropbox.missing_refresh_token: "<yellow>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.</yellow>"
warning.config.host.dropbox.missing_upload_path: "<yellow>Problème trouvé dans config.yml à 'resource-pack.delivery.hosting' - L'argument requis 'upload-path' est manquant pour l'hôte dropbox.</yellow>"
warning.config.host.lobfile.missing_api_key: "<yellow>Problème trouvé dans config.yml à 'resource-pack.delivery.hosting' - L'argument requis 'api-key' est manquant pour l'hôte lobfile.</yellow>"
warning.config.host.onedrive.missing_client_id: "<yellow>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.</yellow>"
warning.config.host.onedrive.missing_client_secret: "<yellow>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.</yellow>"
warning.config.host.onedrive.missing_refresh_token: "<yellow>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.</yellow>"
warning.config.host.onedrive.missing_upload_path: "<yellow>Problème trouvé dans config.yml à 'resource-pack.delivery.hosting' - L'argument requis 'upload-path' est manquant pour l'hôte onedrive.</yellow>"
warning.config.host.s3.missing_endpoint: "<yellow>Problème trouvé dans config.yml à 'resource-pack.delivery.hosting' - L'argument requis 'endpoint' est manquant pour l'hôte s3.</yellow>"
warning.config.host.s3.missing_protocol: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Argument requis 'protocol' manquant pour le host s3.</yellow>"
warning.config.host.s3.missing_bucket: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Argument requis 'bucket' manquant pour le host s3.</yellow>"
warning.config.host.s3.missing_region: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Argument requis 'region' manquant pour le host s3.</yellow>"
warning.config.host.s3.missing_access_key: "<yellow>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.</yellow>"
warning.config.host.s3.missing_secret: "<yellow>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.</yellow>"
warning.config.host.s3.missing_upload_path: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Argument requis 'upload-path' manquant pour le host s3.</yellow>"
warning.config.host.s3.missing_cdn_domain: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Argument requis 'cdn.domain' manquant pour le host s3.</yellow>"
warning.config.host.s3.missing_cdn_protocol: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Argument requis 'cdn.protocol' manquant pour le host s3.</yellow>"
warning.config.host.self.missing_ip: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Argument requis 'ip' manquant pour le host local.</yellow>"
warning.config.host.self.invalid_port: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Port invalide '<arg:0>' pour le host local.</yellow>"
warning.config.host.self.invalid_url: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - URL invalide '<arg:0>' pour le host local.</yellow>"
warning.config.host.gitlab.missing_url: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Argument requis 'gitlab-url' manquant pour le host gitlab.</yellow>"
warning.config.host.gitlab.missing_token: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Argument requis 'access-token' manquant pour le host gitlab.</yellow>"
warning.config.host.gitlab.missing_project: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Argument requis 'project-id' manquant pour le host gitlab.</yellow>"
warning.config.host.proxy.missing_host: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Argument requis 'host' manquant pour le proxy.</yellow>"
warning.config.host.proxy.missing_port: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Argument requis 'port' manquant pour le proxy.</yellow>"
warning.config.host.proxy.missing_scheme: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Argument requis 'scheme' manquant pour le proxy.</yellow>"
warning.config.host.proxy.invalid: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.delivery.hosting' - Proxy invalide '<arg:0>'.</yellow>"
warning.config.conflict_matcher.missing_type: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.duplicated-files-handler' - Argument requis 'type' manquant pour un des gestionnaires.</yellow>"
warning.config.conflict_matcher.invalid_type: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.duplicated-files-handler' - Un des termes utilise un type invalide '<arg:0>'.</yellow>"
warning.config.conflict_matcher.exact.missing_path: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.duplicated-files-handler' - Argument requis 'path' manquant pour le comparateur 'exact'.</yellow>"
warning.config.conflict_matcher.contains.missing_path: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.duplicated-files-handler' - Argument requis 'path' manquant pour le comparateur 'contains'.</yellow>"
warning.config.conflict_matcher.filename.missing_name: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.duplicated-files-handler' - Argument requis 'path' manquant pour le comparateur 'filename'.</yellow>"
warning.config.conflict_matcher.pattern.missing_pattern: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.duplicated-files-handler' - Argument requis 'pattern' manquant pour le comparateur 'pattern'.</yellow>"
warning.config.conflict_matcher.parent_prefix.missing_prefix: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.duplicated-files-handler' - Argument requis 'prefix' manquant pour le comparateur 'parent_path_prefix'.</yellow>"
warning.config.conflict_matcher.parent_suffix.missing_suffix: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.duplicated-files-handler' - Argument requis 'suffix' manquant pour le comparateur 'parent_path_suffix'.</yellow>"
warning.config.conflict_matcher.inverted.missing_term: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.duplicated-files-handler' - Argument requis 'term' manquant pour le comparateur 'inverted'.</yellow>"
warning.config.conflict_matcher.all_of.missing_terms: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.duplicated-files-handler' - Argument requis 'terms' manquant pour le comparateur 'all_of'.</yellow>"
warning.config.conflict_matcher.any_of.missing_terms: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.duplicated-files-handler' - Argument requis 'terms' manquant pour le comparateur 'any_of'.</yellow>"
warning.config.conflict_resolution.missing_type: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.duplicated-files-handler' - Argument requis 'type' manquant pour une des résolutions.</yellow>"
warning.config.conflict_resolution.invalid_type: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.duplicated-files-handler' - Une des résolutions utilise un type invalide '<arg:0>'.</yellow>"
warning.config.event.missing_trigger: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'on' pour les déclencheurs d'événement.</yellow>"
warning.config.event.invalid_trigger: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' utilise un déclencheur d'événement invalide '<arg:2>'.</yellow>"
warning.config.event.condition.missing_type: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'type' pour la condition d'événement.</yellow>"
warning.config.event.condition.invalid_type: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' utilise un argument 'type' invalide '<arg:2>' pour la condition d'événement.</yellow>"
warning.config.function.missing_type: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'type' pour la fonction.</yellow>"
warning.config.function.invalid_type: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' utilise un type de fonction invalide '<arg:2>'.</yellow>"
warning.config.function.command.missing_command: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'command' pour la fonction 'command'.</yellow>"
warning.config.function.actionbar.missing_actionbar: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'actionbar' pour la fonction 'actionbar'.</yellow>"
warning.config.function.message.missing_message: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'message' pour la fonction 'message'.</yellow>"
warning.config.function.open_window.missing_gui_type: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'gui-type' pour la fonction 'open_window'.</yellow>"
warning.config.function.open_window.invalid_gui_type: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' utilise un type de gui invalide '<arg:2>' pour la fonction 'open_window'. Types autorisés : [<arg:3>].</yellow>"
warning.config.function.run.missing_functions: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'functions' pour la fonction 'run'.</yellow>"
warning.config.function.place_block.missing_block_state: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'block-state' pour la fonction 'place_block'.</yellow>"
warning.config.function.set_food.missing_food: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'food' pour la fonction 'set_food'.</yellow>"
warning.config.function.set_saturation.missing_saturation: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'saturation' pour la fonction 'set_saturation'.</yellow>"
warning.config.function.play_sound.missing_sound: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'sound' pour la fonction 'play_sound'.</yellow>"
warning.config.function.particle.missing_particle: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'particle' pour la fonction 'particle'.</yellow>"
warning.config.function.particle.missing_color: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'color' pour la fonction 'particle'.</yellow>"
warning.config.function.particle.missing_from: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'from' pour la fonction 'particle'.</yellow>"
warning.config.function.particle.missing_to: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'to' pour la fonction 'particle'.</yellow>"
warning.config.function.particle.missing_item: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'item' pour la fonction 'particle'.</yellow>"
warning.config.function.particle.missing_block_state: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'block-state' pour la fonction 'particle'.</yellow>"
warning.config.function.leveler_exp.missing_count: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'count' pour la fonction 'leveler_exp'.</yellow>"
warning.config.function.leveler_exp.missing_leveler: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'leveler' pour la fonction 'leveler_exp'.</yellow>"
warning.config.function.leveler_exp.missing_plugin: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'plugin' pour la fonction 'leveler_exp'.</yellow>"
warning.config.function.remove_potion_effect.missing_potion_effect: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'potion-effect' pour la fonction 'remove_potion_effect'.</yellow>"
warning.config.function.potion_effect.missing_potion_effect: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'potion-effect' pour la fonction 'potion_effect'.</yellow>"
warning.config.function.set_cooldown.missing_time: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'time' pour la fonction 'set_cooldown'.</yellow>"
warning.config.function.set_cooldown.missing_id: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'id' pour la fonction 'set_cooldown'.</yellow>"
warning.config.function.remove_cooldown.missing_id: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'id' pour la fonction 'remove_cooldown'.</yellow>"
warning.config.function.mythic_mobs_skill.missing_skill: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'skill' pour la fonction 'mythic_mobs_skill'.</yellow>"
warning.config.function.spawn_furniture.missing_furniture_id: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'furniture-id' pour la fonction 'spawn_furniture'.</yellow>"
warning.config.function.replace_furniture.missing_furniture_id: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'furniture-id' pour la fonction 'replace_furniture'.</yellow>"
warning.config.function.teleport.missing_x: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'x' pour la fonction 'teleport'.</yellow>"
warning.config.function.teleport.missing_y: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'y' pour la fonction 'teleport'.</yellow>"
warning.config.function.teleport.missing_z: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'z' pour la fonction 'teleport'.</yellow>"
warning.config.function.set_variable.missing_name: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'name' pour la fonction 'set_variable'.</yellow>"
warning.config.function.set_variable.missing_value: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'number' ou 'text' pour la fonction 'set_variable'.</yellow>"
warning.config.function.toast.missing_toast: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'toast' pour la fonction 'toast'.</yellow>"
warning.config.function.toast.missing_icon: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'icon' pour la fonction 'toast'.</yellow>"
warning.config.function.toast.invalid_advancement_type: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' utilise un type d'avancement invalide '<arg:2>' pour la fonction 'toast'. Types autorisés : [<arg:3>].</yellow>"
warning.config.function.merchant_trade.missing_offers: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'offers' pour la fonction 'merchant_trade'.</yellow>"
warning.config.function.merchant_trade.offer.missing_cost_1: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'cost-1' pour les offres du marchand.</yellow>"
warning.config.function.merchant_trade.offer.missing_result: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'result' pour les offres du marchand.</yellow>"
warning.config.function.when.missing_source: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'source' pour la fonction 'when'.</yellow>"
warning.config.function.if_else.missing_rules: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'rules' pour la fonction 'if_else'.</yellow>"
warning.config.function.update_block_property.missing_properties: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'properties' pour la fonction 'update_block_property'.</yellow>"
warning.config.function.transform_block.missing_block: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'block' pour la fonction 'transform_block'.</yellow>"
warning.config.selector.missing_type: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' manque l'argument requis 'type' pour le sélecteur.</yellow>"
warning.config.selector.invalid_type: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' utilise un type de sélecteur invalide '<arg:2>'.</yellow>"
warning.config.selector.invalid_target: "<yellow>Problème trouvé dans le fichier <arg:0> - La configuration '<arg:1>' utilise une cible de sélecteur invalide '<arg:2>'.</yellow>"
warning.config.resource_pack.item_model.already_exist: "<yellow>Échec de génération du modèle d'objet pour '<arg:0>' car le fichier '<arg:1>' existe déjà.</yellow>"
warning.config.resource_pack.model.generation.already_exist: "<yellow>Échec de génération du modèle car le fichier modèle '<arg:0>' existe déjà.</yellow>"
warning.config.resource_pack.generation.malformatted_json: "<yellow>Le fichier Json '<arg:0>' est mal formaté.</yellow>"
warning.config.resource_pack.generation.missing_font_texture: "<yellow>La police '<arg:0>' manque la texture requise : '<arg:1>'.</yellow>"
warning.config.resource_pack.generation.missing_model_texture: "<yellow>Le modèle '<arg:0>' manque la texture '<arg:1>'.</yellow>"
warning.config.resource_pack.generation.missing_item_model: "<yellow>L'objet '<arg:0>' manque le fichier modèle : '<arg:1>'.</yellow>"
warning.config.resource_pack.generation.missing_block_model: "<yellow>L'état du bloc '<arg:0>' manque le fichier modèle : '<arg:1>'.</yellow>"
warning.config.resource_pack.generation.missing_parent_model: "<yellow>Le modèle '<arg:0>' ne trouve pas le modèle parent : '<arg:1>'.</yellow>"
warning.config.resource_pack.generation.missing_equipment_texture: "<yellow>L'équipement '<arg:0>' manque la texture '<arg:1>'.</yellow>"
warning.config.resource_pack.generation.missing_sound: "<yellow>L'événement sonore '<arg:0>' manque le fichier ogg '<arg:1>'.</yellow>"
warning.config.resource_pack.generation.texture_not_in_atlas: "<yellow>La texture '<arg:0>' 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.</yellow>"
warning.config.resource_pack.invalid_overlay_format: "<yellow>Problème trouvé dans config.yml en section 'resource-pack.overlay-format' - Format de superposition invalide '<arg:0>'. Le format doit contenir le placeholder '{version}'.</yellow>"
warning.config.equipment.duplicate: "<yellow>Problème trouvé dans le fichier <arg:0> - Équipement dupliqué '<arg:1>'. Vérifiez s'il existe la même configuration dans d'autres fichiers.</yellow>"
warning.config.equipment.missing_type: "<yellow>Problème trouvé dans le fichier <arg:0> - L'équipement '<arg:1>' manque l'argument requis 'type'.</yellow>"
warning.config.equipment.invalid_type: "<yellow>Problème trouvé dans le fichier <arg:0> - L'équipement '<arg:1>' utilise un argument 'type' invalide.</yellow>"
warning.config.equipment.invalid_sacrificed_armor: "<yellow>Problème trouvé dans config.yml en section 'equipment.sacrificed-vanilla-armor' - Type d'armure vanilla invalide '<arg:0>'.</yellow>"
warning.config.image.file_not_found: "<yellow>Problème trouvé dans le fichier <arg:0> - Fichier PNG '<arg:2>' introuvable pour l'image '<arg:1>'.</yellow>"
warning.config.item.model.special.head.missing_texture: "<yellow>Problème trouvé dans le fichier <arg:0> - L'objet '<arg:1>' manque l'argument requis 'texture' pour le modèle spécial 'minecraft:head'.</yellow>"
warning.config.loot_table.condition.table_bonus.missing_enchantment: "<yellow>Problème trouvé dans le fichier <arg:0> - '<arg:1>' a une table de butin mal configurée, la condition 'table_bonus' manque l'argument requis 'enchantment'.</yellow>"
warning.config.loot_table.condition.table_bonus.missing_chances: "<yellow>Problème trouvé dans le fichier <arg:0> - '<arg:1>' a une table de butin mal configurée, la condition 'table_bonus' manque l'argument requis 'chances'.</yellow>"
warning.config.loot_table.number.missing_type: "<yellow>Problème trouvé dans le fichier <arg:0> - '<arg:1>' a une table de butin mal configurée, un des nombres manque l'argument requis 'type'.</yellow>"
warning.config.loot_table.number.invalid_type: "<yellow>Problème trouvé dans le fichier <arg:0> - '<arg:1>' a une table de butin mal configurée, un des nombres utilise un type invalide '<arg:2>'.</yellow>"

View File

@@ -220,6 +220,8 @@ warning.config.item.legacy_model.missing_path: "<yellow>在文件 <arg:0> 发现
warning.config.item.legacy_model.overrides.missing_path: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 的旧版模型覆写规则(overrides)缺少必需的 'path' 参数</yellow>" warning.config.item.legacy_model.overrides.missing_path: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 的旧版模型覆写规则(overrides)缺少必需的 'path' 参数</yellow>"
warning.config.item.legacy_model.overrides.missing_predicate: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 的旧版模型覆写规则(overrides)缺少必需的 'predicate' 参数</yellow>" warning.config.item.legacy_model.overrides.missing_predicate: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 的旧版模型覆写规则(overrides)缺少必需的 'predicate' 参数</yellow>"
warning.config.item.legacy_model.cannot_convert: "<yellow>在文件 <arg:0> 发现问题 - 无法将物品 '<arg:1>' 自动转换为旧版格式, 请手动为此物品创建 'legacy-model' 配置项</yellow>" warning.config.item.legacy_model.cannot_convert: "<yellow>在文件 <arg:0> 发现问题 - 无法将物品 '<arg:1>' 自动转换为旧版格式, 请手动为此物品创建 'legacy-model' 配置项</yellow>"
warning.config.item.simplified_model.invalid_model: "<yellow>在文件 <arg:0> 中发现配置问题 - 物品 '<arg:1>' 包含的参数数量不匹配. 预期模型数量为 '<arg:2>', 但实际数量为 '<arg:3>'</yellow>"
warning.config.item.simplified_model.invalid_texture: "<yellow>在文件 <arg:0> 中发现配置问题 - 物品 '<arg:1>' 包含的参数数量不匹配. 预期纹理数量为 '<arg:2>', 但实际数量为 '<arg:3>'</yellow>"
warning.config.item.model.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 使用了无效的模型类型 '<arg:2>'</yellow>" warning.config.item.model.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 使用了无效的模型类型 '<arg:2>'</yellow>"
warning.config.item.model.tint.missing_type: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 的染色配置缺少必需的 'type' 参数</yellow>" warning.config.item.model.tint.missing_type: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 的染色配置缺少必需的 'type' 参数</yellow>"
warning.config.item.model.tint.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 使用了无效的染色类型 '<arg:2>'</yellow>" warning.config.item.model.tint.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - 物品 '<arg:1>' 使用了无效的染色类型 '<arg:2>'</yellow>"
@@ -353,6 +355,8 @@ warning.config.block.behavior.attached_stem.missing_facing: "<yellow>在文件 <
warning.config.block.behavior.attached_stem.missing_fruit: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'attached_stem_block' 行为缺少必需的 'fruit' 选项</yellow>" warning.config.block.behavior.attached_stem.missing_fruit: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'attached_stem_block' 行为缺少必需的 'fruit' 选项</yellow>"
warning.config.block.behavior.attached_stem.missing_stem: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'attached_stem_block' 行为缺少必需的 'stem' 选项</yellow>" warning.config.block.behavior.attached_stem.missing_stem: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'attached_stem_block' 行为缺少必需的 'stem' 选项</yellow>"
warning.config.block.behavior.chime.missing_sounds_projectile_hit: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'chime_block' 行为缺少必需的 'sounds.projectile-hit' 选项</yellow>" warning.config.block.behavior.chime.missing_sounds_projectile_hit: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'chime_block' 行为缺少必需的 'sounds.projectile-hit' 选项</yellow>"
warning.config.block.behavior.surface_spreading.missing_base_block: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'surface_spreading_block' 行为缺少必需的 'base-block' 选项</yellow>"
warning.config.block.behavior.snowy.missing_snowy: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'snowy_block' 行为缺少必需的 'snowy' 属性</yellow>"
warning.config.model.generation.missing_parent: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 的 'generation' 段落缺少必需的 'parent' 参数</yellow>" warning.config.model.generation.missing_parent: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 的 'generation' 段落缺少必需的 'parent' 参数</yellow>"
warning.config.model.generation.conflict: "<yellow>在文件 <arg:0> 发现问题 - 无法为 '<arg:1>' 生成模型 存在多个配置尝试使用相同路径 '<arg:2>' 生成不同的 JSON 模型</yellow>" warning.config.model.generation.conflict: "<yellow>在文件 <arg:0> 发现问题 - 无法为 '<arg:1>' 生成模型 存在多个配置尝试使用相同路径 '<arg:2>' 生成不同的 JSON 模型</yellow>"
warning.config.model.generation.invalid_display_position: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 在 'generation.display' 区域使用了无效的 display 位置类型 '<arg:2>'. 可用展示类型: [<arg:3>]</yellow>" warning.config.model.generation.invalid_display_position: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 在 'generation.display' 区域使用了无效的 display 位置类型 '<arg:2>'. 可用展示类型: [<arg:3>]</yellow>"
@@ -476,6 +480,7 @@ warning.config.function.when.missing_source: "<yellow>在文件 <arg:0> 发现
warning.config.function.if_else.missing_rules: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'if_else' 函数所需的 'rules' 参数</yellow>" warning.config.function.if_else.missing_rules: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'if_else' 函数所需的 'rules' 参数</yellow>"
warning.config.function.update_block_property.missing_properties: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'update_block_property' 函数所需的 'properties' 参数</yellow>" warning.config.function.update_block_property.missing_properties: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'update_block_property' 函数所需的 'properties' 参数</yellow>"
warning.config.function.transform_block.missing_block: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'transform_block' 函数所需的 'block' 参数</yellow>" warning.config.function.transform_block.missing_block: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'transform_block' 函数所需的 'block' 参数</yellow>"
warning.config.function.cycle_block_property.missing_property: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'cycle_block_property' 函数所需的 'property' 参数</yellow>"
warning.config.selector.missing_type: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少选择器必需的 'type' 参数</yellow>" warning.config.selector.missing_type: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少选择器必需的 'type' 参数</yellow>"
warning.config.selector.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 使用了无效的选择器类型 '<arg:2>'</yellow>" warning.config.selector.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 使用了无效的选择器类型 '<arg:2>'</yellow>"
warning.config.selector.invalid_target: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 使用了无效的选择器目标 '<arg:2>'</yellow>" warning.config.selector.invalid_target: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 使用了无效的选择器目标 '<arg:2>'</yellow>"

View File

@@ -8,6 +8,4 @@ public abstract class AbstractAdvancementManager implements AdvancementManager {
public AbstractAdvancementManager(CraftEngine plugin) { public AbstractAdvancementManager(CraftEngine plugin) {
this.plugin = plugin; this.plugin = plugin;
} }
} }

View File

@@ -752,7 +752,10 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
json.addProperty("x", ResourceConfigUtils.getAsInt(section.get("x"), "x")); json.addProperty("x", ResourceConfigUtils.getAsInt(section.get("x"), "x"));
if (section.containsKey("y")) if (section.containsKey("y"))
json.addProperty("y", ResourceConfigUtils.getAsInt(section.get("y"), "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")) if (section.containsKey("weight"))
json.addProperty("weight", ResourceConfigUtils.getAsInt(section.get("weight"), "weight")); json.addProperty("weight", ResourceConfigUtils.getAsInt(section.get("weight"), "weight"));
Map<String, Object> generationMap = MiscUtils.castToMap(section.get("generation"), true); Map<String, Object> generationMap = MiscUtils.castToMap(section.get("generation"), true);

View File

@@ -138,6 +138,5 @@ public abstract class AbstractCustomBlock implements CustomBlock {
@Override @Override
public void setPlacedBy(BlockPlaceContext context, ImmutableBlockState state) { public void setPlacedBy(BlockPlaceContext context, ImmutableBlockState state) {
this.behavior.setPlacedBy(context, state);
} }
} }

View File

@@ -47,6 +47,11 @@ public enum AutoStateGroup {
TRIPWIRE("tripwire", Set.of(BlockKeys.TRIPWIRE), (w) -> true), TRIPWIRE("tripwire", Set.of(BlockKeys.TRIPWIRE), (w) -> true),
SUGAR_CANE("sugar_cane", Set.of(BlockKeys.SUGAR_CANE), (w) -> true), SUGAR_CANE("sugar_cane", Set.of(BlockKeys.SUGAR_CANE), (w) -> true),
CACTUS("cactus", Set.of(BlockKeys.CACTUS), (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), 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), 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); SOLID("solid", Set.of(BlockKeys.BROWN_MUSHROOM_BLOCK, BlockKeys.RED_MUSHROOM_BLOCK, BlockKeys.MUSHROOM_STEM, BlockKeys.NOTE_BLOCK), (w) -> true);

View File

@@ -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.item.context.UseOnContext;
import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.util.Key; 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.ApiStatus;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -187,6 +189,18 @@ public abstract class BlockBehavior {
public void onProjectileHit(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception { public void onProjectileHit(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
} }
// Level/WorldGenLevel level, BlockPos pos, BlockState state, LivingEntity placer, ItemStack itemStack
public void placeMultiState(Object thisBlock, Object[] args, Callable<Object> 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) { public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) {
return state; return state;
} }
@@ -208,9 +222,6 @@ public abstract class BlockBehavior {
return state.settings().replaceable(); return state.settings().replaceable();
} }
public void setPlacedBy(BlockPlaceContext context, ImmutableBlockState state) {
}
public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) { public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) {
return InteractionResult.TRY_EMPTY_HAND; return InteractionResult.TRY_EMPTY_HAND;
} }

View File

@@ -45,6 +45,10 @@ public final class BlockKeys {
public static final Key CHISELED_BOOKSHELF = Key.of("minecraft:chiseled_bookshelf"); public static final Key CHISELED_BOOKSHELF = Key.of("minecraft:chiseled_bookshelf");
public static final Key LECTERN = Key.of("minecraft:lectern"); public static final Key LECTERN = Key.of("minecraft:lectern");
public static final Key FARMLAND = Key.of("minecraft:farmland"); 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 CHEST = Key.of("minecraft:chest");
public static final Key BARREL = Key.of("minecraft:barrel"); public static final Key BARREL = Key.of("minecraft:barrel");

View File

@@ -23,10 +23,14 @@ public interface BlockStateWrapper extends Comparable<BlockStateWrapper> {
BlockStateWrapper withProperty(String propertyName, String propertyValue); BlockStateWrapper withProperty(String propertyName, String propertyValue);
BlockStateWrapper cycleProperty(String propertyName, boolean backwards);
String getAsString(); String getAsString();
boolean isCustom(); boolean isCustom();
boolean isAir();
@Override @Override
default int compareTo(@NotNull BlockStateWrapper o) { default int compareTo(@NotNull BlockStateWrapper o) {
return Integer.compare(registryId(), o.registryId()); return Integer.compare(registryId(), o.registryId());

View File

@@ -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.ContextHolder;
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
import net.momirealms.craftengine.core.registry.Holder; 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.CEWorld;
import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.World;
import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.CompoundTag;
@@ -152,6 +153,16 @@ public final class ImmutableBlockState {
return this.owner; return this.owner;
} }
public <T extends Comparable<T>> ImmutableBlockState cycle(Property<T> property, boolean backwards) {
T currentValue = get(property);
List<T> values = property.possibleValues();
return with(property, getRelative(values, currentValue, backwards));
}
private static <T> T getRelative(List<T> values, T currentValue, boolean backwards) {
return backwards ? MiscUtils.findPreviousInIterable(values, currentValue) : getNextValue(values, currentValue);
}
public <T extends Comparable<T>> ImmutableBlockState cycle(Property<T> property) { public <T extends Comparable<T>> ImmutableBlockState cycle(Property<T> property) {
T currentValue = get(property); T currentValue = get(property);
List<T> values = property.possibleValues(); List<T> values = property.possibleValues();

View File

@@ -16,4 +16,12 @@ public interface StatePropertyAccessor {
@NotNull @NotNull
Object withProperty(String propertyName, String value); Object withProperty(String propertyName, String value);
@NotNull
default Object cycleProperty(String propertyName) {
return cycleProperty(propertyName, false);
}
@NotNull
Object cycleProperty(String propertyName, boolean backwards);
} }

View File

@@ -1,4 +1,4 @@
package net.momirealms.craftengine.core.block.behavior.special; package net.momirealms.craftengine.core.block.behavior;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;

View File

@@ -1,4 +1,4 @@
package net.momirealms.craftengine.core.block.behavior.special; package net.momirealms.craftengine.core.block.behavior;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;

Some files were not shown because too many files have changed in this diff Show More