diff --git a/README.md b/README.md index 329a9045e..d0bcb1fdc 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here! ## Supported Versions -Geyser is currently supporting Minecraft Bedrock 1.20.80 - 1.21.44 and Minecraft Java 1.21/1.21.1. For more information, please see [here](https://geysermc.org/wiki/geyser/supported-versions/). +Geyser is currently supporting Minecraft Bedrock 1.20.80 - 1.21.44 and Minecraft Java 1.21.2/1.21.3. For more information, please see [here](https://geysermc.org/wiki/geyser/supported-versions/). ## Setting Up Take a look [here](https://geysermc.org/wiki/geyser/setup/) for how to set up Geyser. diff --git a/bootstrap/mod/fabric/build.gradle.kts b/bootstrap/mod/fabric/build.gradle.kts index 56bec322e..2599a47b5 100644 --- a/bootstrap/mod/fabric/build.gradle.kts +++ b/bootstrap/mod/fabric/build.gradle.kts @@ -46,7 +46,6 @@ tasks.withType { relocate("org.cloudburstmc.netty") relocate("org.cloudburstmc.protocol") -relocate("com.github.steveice10.mc.auth") tasks { remapJar { diff --git a/bootstrap/mod/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricBootstrap.java b/bootstrap/mod/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricBootstrap.java index 149246d59..96a60322b 100644 --- a/bootstrap/mod/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricBootstrap.java +++ b/bootstrap/mod/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricBootstrap.java @@ -32,7 +32,7 @@ import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.commands.CommandSourceStack; -import net.minecraft.world.entity.player.Player; +import net.minecraft.server.level.ServerPlayer; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.command.CommandRegistry; import org.geysermc.geyser.command.CommandSourceConverter; @@ -80,7 +80,7 @@ public class GeyserFabricBootstrap extends GeyserModBootstrap implements ModInit var sourceConverter = CommandSourceConverter.layered( CommandSourceStack.class, id -> getServer().getPlayerList().getPlayer(id), - Player::createCommandSourceStack, + ServerPlayer::createCommandSourceStack, () -> getServer().createCommandSourceStack(), // NPE if method reference is used, since server is not available yet ModCommandSource::new ); diff --git a/bootstrap/mod/fabric/src/main/resources/fabric.mod.json b/bootstrap/mod/fabric/src/main/resources/fabric.mod.json index 262f9833a..a801eb207 100644 --- a/bootstrap/mod/fabric/src/main/resources/fabric.mod.json +++ b/bootstrap/mod/fabric/src/main/resources/fabric.mod.json @@ -23,8 +23,8 @@ "geyser.mixins.json" ], "depends": { - "fabricloader": ">=0.15.11", + "fabricloader": ">=0.16.7", "fabric": "*", - "minecraft": ">=1.21" + "minecraft": ">=1.21.2" } } diff --git a/bootstrap/mod/neoforge/build.gradle.kts b/bootstrap/mod/neoforge/build.gradle.kts index 4ab005b4f..23f16d64e 100644 --- a/bootstrap/mod/neoforge/build.gradle.kts +++ b/bootstrap/mod/neoforge/build.gradle.kts @@ -13,6 +13,9 @@ architectury { provided("org.cloudburstmc.math", "api") provided("com.google.errorprone", "error_prone_annotations") +// Jackson shipped by Minecraft is too old, so we shade & relocate our newer version +relocate("com.fasterxml.jackson") + val includeTransitive: Configuration = configurations.getByName("includeTransitive") dependencies { @@ -31,6 +34,12 @@ dependencies { } shadow(projects.core) { isTransitive = false } + // Minecraft (1.21.2+) includes jackson. But an old version! + shadow(libs.jackson.core) { isTransitive = false } + shadow(libs.jackson.databind) { isTransitive = false } + shadow(libs.jackson.dataformat.yaml) { isTransitive = false } + shadow(libs.jackson.annotations) { isTransitive = false } + // Let's shade in our own api shadow(projects.api) { isTransitive = false } @@ -56,6 +65,11 @@ tasks { remapModrinthJar { archiveBaseName.set("geyser-neoforge") } + + shadowJar { + // Without this, jackson's service files are not relocated + mergeServiceFiles() + } } modrinth { diff --git a/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgeBootstrap.java b/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgeBootstrap.java index ad56eda39..aa731befc 100644 --- a/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgeBootstrap.java +++ b/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgeBootstrap.java @@ -26,7 +26,7 @@ package org.geysermc.geyser.platform.neoforge; import net.minecraft.commands.CommandSourceStack; -import net.minecraft.world.entity.player.Player; +import net.minecraft.server.level.ServerPlayer; import net.neoforged.bus.api.EventPriority; import net.neoforged.fml.ModContainer; import net.neoforged.fml.common.Mod; @@ -72,7 +72,7 @@ public class GeyserNeoForgeBootstrap extends GeyserModBootstrap { var sourceConverter = CommandSourceConverter.layered( CommandSourceStack.class, id -> getServer().getPlayerList().getPlayer(id), - Player::createCommandSourceStack, + ServerPlayer::createCommandSourceStack, () -> getServer().createCommandSourceStack(), ModCommandSource::new ); @@ -104,7 +104,9 @@ public class GeyserNeoForgeBootstrap extends GeyserModBootstrap { } private void onPlayerJoin(PlayerEvent.PlayerLoggedInEvent event) { - GeyserModUpdateListener.onPlayReady(event.getEntity()); + if (event.getEntity() instanceof ServerPlayer player) { + GeyserModUpdateListener.onPlayReady(player); + } } @Override diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModCompressionDisabler.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModCompressionDisabler.java index 631a21510..89ca53544 100644 --- a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModCompressionDisabler.java +++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModCompressionDisabler.java @@ -28,8 +28,8 @@ package org.geysermc.geyser.platform.mod; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelOutboundHandlerAdapter; import io.netty.channel.ChannelPromise; -import net.minecraft.network.protocol.login.ClientboundGameProfilePacket; import net.minecraft.network.protocol.login.ClientboundLoginCompressionPacket; +import net.minecraft.network.protocol.login.ClientboundLoginFinishedPacket; /** * Disables the compression packet (and the compression handlers from being added to the pipeline) for Geyser clients @@ -45,7 +45,7 @@ public class GeyserModCompressionDisabler extends ChannelOutboundHandlerAdapter Class msgClass = msg.getClass(); // Don't let any compression packet get through if (!ClientboundLoginCompressionPacket.class.isAssignableFrom(msgClass)) { - if (ClientboundGameProfilePacket.class.isAssignableFrom(msgClass)) { + if (ClientboundLoginFinishedPacket.class.isAssignableFrom(msgClass)) { // We're past the point that a compression packet can be sent, so we can safely yeet ourselves away ctx.channel().pipeline().remove(this); diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModUpdateListener.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModUpdateListener.java index 6a724155f..ec34766dc 100644 --- a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModUpdateListener.java +++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModUpdateListener.java @@ -25,13 +25,13 @@ package org.geysermc.geyser.platform.mod; -import net.minecraft.world.entity.player.Player; +import net.minecraft.server.level.ServerPlayer; import org.geysermc.geyser.Permissions; import org.geysermc.geyser.platform.mod.command.ModCommandSource; import org.geysermc.geyser.util.VersionCheckUtils; public final class GeyserModUpdateListener { - public static void onPlayReady(Player player) { + public static void onPlayReady(ServerPlayer player) { // Should be creating this in the supplier, but we need it for the permission check. // Not a big deal currently because ModCommandSource doesn't load locale, so don't need to try to wait for it. ModCommandSource source = new ModCommandSource(player.createCommandSourceStack()); diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/world/GeyserModWorldManager.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/world/GeyserModWorldManager.java index 89452eba3..f85b6e079 100644 --- a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/world/GeyserModWorldManager.java +++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/world/GeyserModWorldManager.java @@ -33,8 +33,10 @@ import net.minecraft.core.component.DataComponents; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BannerBlockEntity; @@ -43,7 +45,6 @@ import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.DecoratedPotBlockEntity; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.status.ChunkStatus; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3i; import org.geysermc.geyser.level.GeyserWorldManager; @@ -84,16 +85,17 @@ public class GeyserModWorldManager extends GeyserWorldManager { } Level level = player.level(); - if (y < level.getMinBuildHeight()) { + if (y < level.getMinY()) { return 0; } - ChunkAccess chunk = level.getChunkSource().getChunk(x >> 4, z >> 4, ChunkStatus.FULL, false); + // Only loads active chunks, and doesn't delegate to main thread + ChunkAccess chunk = ((ServerChunkCache) level.getChunkSource()).chunkMap.getChunkToSend(ChunkPos.asLong(x >> 4, z >> 4)); if (chunk == null) { return 0; } - int worldOffset = level.getMinBuildHeight() >> 4; + int worldOffset = level.getMinY() >> 4; int chunkOffset = (y >> 4) - worldOffset; if (chunkOffset < chunk.getSections().length) { LevelChunkSection section = chunk.getSections()[chunkOffset]; diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneLogger.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneLogger.java index 21e6a5e82..b614a7b23 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneLogger.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneLogger.java @@ -33,10 +33,24 @@ import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.text.ChatColor; +import org.jline.reader.Candidate; +import org.jline.reader.LineReader; +import org.jline.reader.LineReaderBuilder; @Slf4j public class GeyserStandaloneLogger extends SimpleTerminalConsole implements GeyserLogger, GeyserCommandSource { + @Override + protected LineReader buildReader(LineReaderBuilder builder) { + builder.completer((reader, line, candidates) -> { + var suggestions = GeyserImpl.getInstance().commandRegistry().suggestionsFor(this, line.line()); + for (var suggestion : suggestions.list()) { + candidates.add(new Candidate(suggestion.suggestion())); + } + }); + return super.buildReader(builder); + } + @Override protected boolean isRunning() { return !GeyserImpl.getInstance().isShuttingDown(); diff --git a/build-logic/src/main/kotlin/geyser.modrinth-uploading-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.modrinth-uploading-conventions.gradle.kts index d2e207fa4..59f85d182 100644 --- a/build-logic/src/main/kotlin/geyser.modrinth-uploading-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.modrinth-uploading-conventions.gradle.kts @@ -7,12 +7,13 @@ tasks.modrinth.get().dependsOn(tasks.modrinthSyncBody) modrinth { token.set(System.getenv("MODRINTH_TOKEN") ?: "") // Even though this is the default value, apparently this prevents GitHub Actions caching the token? + debugMode.set(System.getenv("MODRINTH_TOKEN") == null) projectId.set("geyser") versionName.set(versionName(project)) versionNumber.set(projectVersion(project)) versionType.set("beta") changelog.set(System.getenv("CHANGELOG") ?: "") - gameVersions.addAll("1.21", libs.minecraft.get().version as String) + gameVersions.addAll("1.21.2", libs.minecraft.get().version as String) failSilently.set(true) syncBodyFrom.set(rootProject.file("README.md").readText()) diff --git a/core/src/main/java/org/geysermc/geyser/command/CommandRegistry.java b/core/src/main/java/org/geysermc/geyser/command/CommandRegistry.java index 54681abea..838ab71b1 100644 --- a/core/src/main/java/org/geysermc/geyser/command/CommandRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/command/CommandRegistry.java @@ -27,6 +27,13 @@ package org.geysermc.geyser.command; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import org.checkerframework.checker.nullness.qual.NonNull; +import org.cloudburstmc.protocol.bedrock.data.command.CommandData; +import org.cloudburstmc.protocol.bedrock.data.command.CommandEnumConstraint; +import org.cloudburstmc.protocol.bedrock.data.command.CommandEnumData; +import org.cloudburstmc.protocol.bedrock.data.command.CommandOverloadData; +import org.cloudburstmc.protocol.bedrock.data.command.CommandParam; +import org.cloudburstmc.protocol.bedrock.data.command.CommandParamData; +import org.cloudburstmc.protocol.bedrock.data.command.CommandPermission; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.command.Command; import org.geysermc.geyser.api.event.EventRegistrar; @@ -51,14 +58,29 @@ import org.geysermc.geyser.command.defaults.StopCommand; import org.geysermc.geyser.command.defaults.VersionCommand; import org.geysermc.geyser.event.type.GeyserDefineCommandsEventImpl; import org.geysermc.geyser.extension.command.GeyserExtensionCommand; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; import org.incendo.cloud.Command.Builder; import org.incendo.cloud.CommandManager; import org.incendo.cloud.execution.ExecutionCoordinator; +import org.incendo.cloud.internal.CommandNode; +import org.incendo.cloud.parser.standard.EnumParser; +import org.incendo.cloud.parser.standard.IntegerParser; +import org.incendo.cloud.parser.standard.LiteralParser; +import org.incendo.cloud.parser.standard.StringArrayParser; +import org.incendo.cloud.suggestion.Suggestion; +import org.incendo.cloud.suggestion.Suggestions; +import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; import java.util.Map; +import java.util.Set; import static org.geysermc.geyser.command.GeyserCommand.DEFAULT_ROOT_COMMAND; @@ -299,4 +321,90 @@ public class CommandRegistry implements EventRegistrar { public void runCommand(@NonNull GeyserCommandSource source, @NonNull String command) { cloud.commandExecutor().executeCommand(source, command); } + + public Suggestions suggestionsFor(GeyserCommandSource source, String input) { + return cloud.suggestionFactory().suggestImmediately(source, input); + } + + public void export(GeyserSession session, List bedrockCommands, Set knownAliases) { + cloud.commandTree().rootNodes().forEach(commandTree -> { + var command = commandTree.command(); + // Command null happens if you register an extension command with custom Cloud parameters... + if (command == null || session.hasPermission(command.commandPermission().permissionString())) { + var rootComponent = commandTree.component(); + String name = rootComponent.name(); + if (!knownAliases.add(name)) { + // If the server already defined the command, let's not crash. + return; + } + + LinkedHashMap> values = new LinkedHashMap<>(); + for (String s : rootComponent.aliases()) { + values.put(s, EnumSet.of(CommandEnumConstraint.ALLOW_ALIASES)); + } + CommandEnumData aliases = new CommandEnumData(name + "Aliases", values, false); + + List data = new ArrayList<>(); + for (var node : commandTree.children()) { + List> params = createParamData(session, node); + params.forEach(param -> data.add(new CommandOverloadData(false, param.toArray(CommandParamData[]::new)))); + } + + CommandData bedrockCommand = new CommandData(name, rootComponent.description().textDescription(), + Set.of(CommandData.Flag.NOT_CHEAT), CommandPermission.ANY, aliases, + Collections.emptyList(), data.toArray(new CommandOverloadData[0])); + bedrockCommands.add(bedrockCommand); + } + }); + } + + private List> createParamData(GeyserSession session, CommandNode node) { + var command = node.command(); + if (command != null && !session.hasPermission(command.commandPermission().permissionString())) { + // Triggers with subcommands like Geyser dump, stop, etc. + return Collections.emptyList(); + } + + CommandParamData data = new CommandParamData(); + var component = node.component(); + data.setName(component.name()); + data.setOptional(component.optional()); + var suggestionProvider = component.suggestionProvider(); + if (suggestionProvider instanceof LiteralParser parser) { + Map> values = new LinkedHashMap<>(); + for (String alias : parser.aliases()) { + values.put(alias, Set.of()); + } + + data.setEnumData(new CommandEnumData(component.name(), values, false)); + } else if (suggestionProvider instanceof IntegerParser) { + data.setType(CommandParam.INT); + } else if (suggestionProvider instanceof EnumParser parser) { + LinkedHashMap> map = new LinkedHashMap<>(); + for (Enum e : parser.acceptedValues()) { + map.put(e.name().toLowerCase(Locale.ROOT), Set.of()); + } + + data.setEnumData(new CommandEnumData(component.name().toLowerCase(Locale.ROOT), map, false)); + } else if (component.parser() instanceof StringArrayParser) { + data.setType(CommandParam.TEXT); + } else { + data.setType(CommandParam.STRING); + } + + var children = node.children(); + if (children.isEmpty()) { + List list = new ArrayList<>(); // Must be mutable; parents will be added to list. + list.add(data); + return Collections.singletonList(list); // Safe to do; will be consumed in an addAll call. + } + List> collectiveData = new ArrayList<>(); + // If a node has multiple children, this will need to be represented + // by creating a new list/branch for each and cloning this node down each line. + for (var child : children) { + collectiveData.addAll(createParamData(session, child)); + } + collectiveData.forEach(list -> list.add(0, data)); + return collectiveData; + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java index 391130146..a25861813 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -151,29 +151,37 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatE import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; public final class EntityDefinitions { + public static final EntityDefinition ACACIA_BOAT; + public static final EntityDefinition ACACIA_CHEST_BOAT; public static final EntityDefinition ALLAY; public static final EntityDefinition AREA_EFFECT_CLOUD; public static final EntityDefinition ARMADILLO; public static final EntityDefinition ARMOR_STAND; public static final EntityDefinition ARROW; public static final EntityDefinition AXOLOTL; + public static final EntityDefinition BAMBOO_RAFT; + public static final EntityDefinition BAMBOO_CHEST_RAFT; public static final EntityDefinition BAT; public static final EntityDefinition BEE; + public static final EntityDefinition BIRCH_BOAT; + public static final EntityDefinition BIRCH_CHEST_BOAT; public static final EntityDefinition BLAZE; - public static final EntityDefinition BOAT; public static final EntityDefinition BOGGED; public static final EntityDefinition BREEZE; public static final EntityDefinition BREEZE_WIND_CHARGE; public static final EntityDefinition CAMEL; public static final EntityDefinition CAT; public static final EntityDefinition CAVE_SPIDER; + public static final EntityDefinition CHERRY_BOAT; + public static final EntityDefinition CHERRY_CHEST_BOAT; public static final EntityDefinition CHEST_MINECART; public static final EntityDefinition CHICKEN; - public static final EntityDefinition CHEST_BOAT; public static final EntityDefinition COD; public static final EntityDefinition COMMAND_BLOCK_MINECART; public static final EntityDefinition COW; public static final EntityDefinition CREEPER; + public static final EntityDefinition DARK_OAK_BOAT; + public static final EntityDefinition DARK_OAK_CHEST_BOAT; public static final EntityDefinition DOLPHIN; public static final EntityDefinition DONKEY; public static final EntityDefinition DRAGON_FIREBALL; @@ -212,14 +220,20 @@ public final class EntityDefinitions { public static final EntityDefinition IRON_GOLEM; public static final EntityDefinition ITEM; public static final EntityDefinition ITEM_FRAME; + public static final EntityDefinition JUNGLE_BOAT; + public static final EntityDefinition JUNGLE_CHEST_BOAT; public static final EntityDefinition LEASH_KNOT; public static final EntityDefinition LIGHTNING_BOLT; public static final EntityDefinition LLAMA; public static final EntityDefinition LLAMA_SPIT; public static final EntityDefinition MAGMA_CUBE; + public static final EntityDefinition MANGROVE_BOAT; + public static final EntityDefinition MANGROVE_CHEST_BOAT; public static final EntityDefinition MINECART; public static final EntityDefinition MOOSHROOM; public static final EntityDefinition MULE; + public static final EntityDefinition OAK_BOAT; + public static final EntityDefinition OAK_CHEST_BOAT; public static final EntityDefinition OCELOT; public static final EntityDefinition PAINTING; public static final EntityDefinition PANDA; @@ -250,6 +264,8 @@ public final class EntityDefinitions { public static final EntityDefinition SPAWNER_MINECART; // Not present on Bedrock public static final EntityDefinition SPECTRAL_ARROW; public static final EntityDefinition SPIDER; + public static final EntityDefinition SPRUCE_BOAT; + public static final EntityDefinition SPRUCE_CHEST_BOAT; public static final EntityDefinition SQUID; public static final EntityDefinition STRAY; public static final EntityDefinition STRIDER; @@ -308,23 +324,6 @@ public final class EntityDefinitions { .addTranslator(null) // Waiting .addTranslator(MetadataType.PARTICLE, AreaEffectCloudEntity::setParticle) .build(); - BOAT = EntityDefinition.inherited(BoatEntity::new, entityBase) - .type(EntityType.BOAT) - .height(0.6f).width(1.6f) - .offset(0.35f) - .addTranslator(MetadataType.INT, (boatEntity, entityMetadata) -> boatEntity.getDirtyMetadata().put(EntityDataTypes.HURT_TICKS, entityMetadata.getValue())) // Time since last hit - .addTranslator(MetadataType.INT, (boatEntity, entityMetadata) -> boatEntity.getDirtyMetadata().put(EntityDataTypes.HURT_DIRECTION, entityMetadata.getValue())) // Rocking direction - .addTranslator(MetadataType.FLOAT, (boatEntity, entityMetadata) -> - // 'Health' in Bedrock, damage taken in Java - it makes motion in Bedrock - boatEntity.getDirtyMetadata().put(EntityDataTypes.STRUCTURAL_INTEGRITY, 40 - ((int) ((FloatEntityMetadata) entityMetadata).getPrimitiveValue()))) - .addTranslator(MetadataType.INT, BoatEntity::setVariant) - .addTranslator(MetadataType.BOOLEAN, BoatEntity::setPaddlingLeft) - .addTranslator(MetadataType.BOOLEAN, BoatEntity::setPaddlingRight) - .addTranslator(MetadataType.INT, (boatEntity, entityMetadata) -> boatEntity.getDirtyMetadata().put(EntityDataTypes.BOAT_BUBBLE_TIME, entityMetadata.getValue())) // May not actually do anything - .build(); - CHEST_BOAT = EntityDefinition.inherited(ChestBoatEntity::new, BOAT) - .type(EntityType.CHEST_BOAT) - .build(); DRAGON_FIREBALL = EntityDefinition.inherited(FireballEntity::new, entityBase) .type(EntityType.DRAGON_FIREBALL) .heightAndWidth(1.0f) @@ -567,6 +566,45 @@ public final class EntityDefinitions { .build(false); } + // Boats + { + EntityDefinition boatBase = EntityDefinition.inherited(null, entityBase) + .height(0.6f).width(1.6f) + .offset(0.35f) + .addTranslator(MetadataType.INT, (boatEntity, entityMetadata) -> boatEntity.getDirtyMetadata().put(EntityDataTypes.HURT_TICKS, entityMetadata.getValue())) // Time since last hit + .addTranslator(MetadataType.INT, (boatEntity, entityMetadata) -> boatEntity.getDirtyMetadata().put(EntityDataTypes.HURT_DIRECTION, entityMetadata.getValue())) // Rocking direction + .addTranslator(MetadataType.FLOAT, (boatEntity, entityMetadata) -> + // 'Health' in Bedrock, damage taken in Java - it makes motion in Bedrock + boatEntity.getDirtyMetadata().put(EntityDataTypes.STRUCTURAL_INTEGRITY, 40 - ((int) ((FloatEntityMetadata) entityMetadata).getPrimitiveValue()))) + .addTranslator(MetadataType.BOOLEAN, BoatEntity::setPaddlingLeft) + .addTranslator(MetadataType.BOOLEAN, BoatEntity::setPaddlingRight) + .addTranslator(MetadataType.INT, (boatEntity, entityMetadata) -> boatEntity.getDirtyMetadata().put(EntityDataTypes.BOAT_BUBBLE_TIME, entityMetadata.getValue())) // May not actually do anything + .build(); + + ACACIA_BOAT = buildBoat(boatBase, EntityType.ACACIA_BOAT, BoatEntity.BoatVariant.ACACIA); + BAMBOO_RAFT = buildBoat(boatBase, EntityType.BAMBOO_RAFT, BoatEntity.BoatVariant.BAMBOO); + BIRCH_BOAT = buildBoat(boatBase, EntityType.BIRCH_BOAT, BoatEntity.BoatVariant.BIRCH); + CHERRY_BOAT = buildBoat(boatBase, EntityType.CHERRY_BOAT, BoatEntity.BoatVariant.CHERRY); + DARK_OAK_BOAT = buildBoat(boatBase, EntityType.DARK_OAK_BOAT, BoatEntity.BoatVariant.DARK_OAK); + JUNGLE_BOAT = buildBoat(boatBase, EntityType.JUNGLE_BOAT, BoatEntity.BoatVariant.JUNGLE); + MANGROVE_BOAT = buildBoat(boatBase, EntityType.MANGROVE_BOAT, BoatEntity.BoatVariant.MANGROVE); + OAK_BOAT = buildBoat(boatBase, EntityType.OAK_BOAT, BoatEntity.BoatVariant.OAK); + SPRUCE_BOAT = buildBoat(boatBase, EntityType.SPRUCE_BOAT, BoatEntity.BoatVariant.SPRUCE); + + EntityDefinition chestBoatBase = EntityDefinition.inherited(null, boatBase) + .build(); + + ACACIA_CHEST_BOAT = buildChestBoat(chestBoatBase, EntityType.ACACIA_CHEST_BOAT, BoatEntity.BoatVariant.ACACIA); + BAMBOO_CHEST_RAFT = buildChestBoat(chestBoatBase, EntityType.BAMBOO_CHEST_RAFT, BoatEntity.BoatVariant.BAMBOO); + BIRCH_CHEST_BOAT = buildChestBoat(chestBoatBase, EntityType.BIRCH_CHEST_BOAT, BoatEntity.BoatVariant.BIRCH); + CHERRY_CHEST_BOAT = buildChestBoat(chestBoatBase, EntityType.CHERRY_CHEST_BOAT, BoatEntity.BoatVariant.CHERRY); + DARK_OAK_CHEST_BOAT = buildChestBoat(chestBoatBase, EntityType.DARK_OAK_CHEST_BOAT, BoatEntity.BoatVariant.DARK_OAK); + JUNGLE_CHEST_BOAT = buildChestBoat(chestBoatBase, EntityType.JUNGLE_CHEST_BOAT, BoatEntity.BoatVariant.JUNGLE); + MANGROVE_CHEST_BOAT = buildChestBoat(chestBoatBase, EntityType.MANGROVE_CHEST_BOAT, BoatEntity.BoatVariant.MANGROVE); + OAK_CHEST_BOAT = buildChestBoat(chestBoatBase, EntityType.OAK_CHEST_BOAT, BoatEntity.BoatVariant.OAK); + SPRUCE_CHEST_BOAT = buildChestBoat(chestBoatBase, EntityType.SPRUCE_CHEST_BOAT, BoatEntity.BoatVariant.SPRUCE); + } + EntityDefinition livingEntityBase = EntityDefinition.inherited(LivingEntity::new, entityBase) .addTranslator(MetadataType.BYTE, LivingEntity::setLivingEntityFlags) .addTranslator(MetadataType.FLOAT, LivingEntity::setHealth) @@ -640,14 +678,6 @@ public final class EntityDefinitions { .addTranslator(MetadataType.BOOLEAN, (entity, entityMetadata) -> entity.setFlag(EntityFlag.POWERED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) .addTranslator(MetadataType.BOOLEAN, CreeperEntity::setIgnited) .build(); - DOLPHIN = EntityDefinition.inherited(DolphinEntity::new, mobEntityBase) - .type(EntityType.DOLPHIN) - .height(0.6f).width(0.9f) - //TODO check - .addTranslator(null) // treasure position - .addTranslator(null) // "got fish" - .addTranslator(null) // "moistness level" - .build(); ENDERMAN = EntityDefinition.inherited(EndermanEntity::new, mobEntityBase) .type(EntityType.ENDERMAN) .height(2.9f).width(0.6f) @@ -717,10 +747,6 @@ public final class EntityDefinitions { .type(EntityType.CAVE_SPIDER) .height(0.5f).width(0.7f) .build(); - SQUID = EntityDefinition.inherited(SquidEntity::new, mobEntityBase) - .type(EntityType.SQUID) - .heightAndWidth(0.8f) - .build(); STRAY = EntityDefinition.inherited(AbstractSkeletonEntity::new, mobEntityBase) .type(EntityType.STRAY) .height(1.8f).width(0.6f) @@ -819,6 +845,7 @@ public final class EntityDefinitions { SALMON = EntityDefinition.inherited(abstractFishEntityBase.factory(), abstractFishEntityBase) .type(EntityType.SALMON) .height(0.5f).width(0.7f) + .addTranslator(null) // Scale/variant - TODO .build(); TADPOLE = EntityDefinition.inherited(TadpoleEntity::new, abstractFishEntityBase) .type(EntityType.TADPOLE) @@ -846,11 +873,6 @@ public final class EntityDefinitions { .height(1.95f).width(0.6f) .build(); - GLOW_SQUID = EntityDefinition.inherited(GlowSquidEntity::new, SQUID) - .type(EntityType.GLOW_SQUID) - .addTranslator(null) // Set dark ticks remaining, possible TODO - .build(); - EntityDefinition raidParticipantEntityBase = EntityDefinition.inherited(RaidParticipantEntity::new, mobEntityBase) .addTranslator(null) // Celebrating //TODO .build(); @@ -1042,6 +1064,26 @@ public final class EntityDefinitions { .build(); } + // Water creatures (AgeableWaterCreature) + { + DOLPHIN = EntityDefinition.inherited(DolphinEntity::new, ageableEntityBase) + .type(EntityType.DOLPHIN) + .height(0.6f).width(0.9f) + //TODO check + .addTranslator(null) // treasure position + .addTranslator(null) // "got fish" + .addTranslator(null) // "moistness level" + .build(); + SQUID = EntityDefinition.inherited(SquidEntity::new, ageableEntityBase) + .type(EntityType.SQUID) + .heightAndWidth(0.8f) + .build(); + GLOW_SQUID = EntityDefinition.inherited(GlowSquidEntity::new, SQUID) + .type(EntityType.GLOW_SQUID) + .addTranslator(null) // Set dark ticks remaining, possible TODO + .build(); + } + // Horses { EntityDefinition abstractHorseEntityBase = EntityDefinition.inherited(AbstractHorseEntity::new, ageableEntityBase) @@ -1124,6 +1166,22 @@ public final class EntityDefinitions { Registries.JAVA_ENTITY_IDENTIFIERS.get().put("minecraft:marker", null); // We don't need an entity definition for this as it is never sent over the network } + private static EntityDefinition buildBoat(EntityDefinition base, EntityType entityType, BoatEntity.BoatVariant variant) { + return EntityDefinition.inherited((session, javaId, bedrockId, uuid, definition, position, motion, yaw, pitch, headYaw) -> + new BoatEntity(session, javaId, bedrockId, uuid, definition, position, motion, yaw, variant), base) + .type(entityType) + .identifier("minecraft:boat") + .build(); + } + + private static EntityDefinition buildChestBoat(EntityDefinition base, EntityType entityType, BoatEntity.BoatVariant variant) { + return EntityDefinition.inherited((session, javaId, bedrockId, uuid, definition, position, motion, yaw, pitch, headYaw) -> + new ChestBoatEntity(session, javaId, bedrockId, uuid, definition, position, motion, yaw, variant), base) + .type(entityType) + .identifier("minecraft:chest_boat") + .build(); + } + public static void init() { // no-op } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/BoatEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/BoatEntity.java index 47ae6777a..86accea17 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/BoatEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/BoatEntity.java @@ -32,12 +32,14 @@ import org.cloudburstmc.protocol.bedrock.packet.AnimatePacket; import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinitions; +import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; -import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundPaddleBoatPacket; import java.util.UUID; @@ -63,16 +65,19 @@ public class BoatEntity extends Entity implements Leashable, Tickable { * Saved for using the "pick" functionality on a boat. */ @Getter - private int variant; + protected final BoatVariant variant; private long leashHolderBedrockId = -1; // Looks too fast and too choppy with 0.1f, which is how I believe the Microsoftian client handles it private final float ROWING_SPEED = 0.1f; - public BoatEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public BoatEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, BoatVariant variant) { // Initial rotation is incorrect super(session, entityId, geyserId, uuid, definition, position.add(0d, definition.offset(), 0d), motion, yaw + 90, 0, yaw + 90); + this.variant = variant; + + dirtyMetadata.put(EntityDataTypes.VARIANT, variant.ordinal()); // Required to be able to move on land 1.16.200+ or apply gravity not in the water 1.16.100+ dirtyMetadata.put(EntityDataTypes.IS_BUOYANT, true); @@ -124,15 +129,6 @@ public class BoatEntity extends Entity implements Leashable, Tickable { moveRelative(0, 0, 0, yaw + 90, 0, 0, isOnGround); } - public void setVariant(IntEntityMetadata entityMetadata) { - variant = entityMetadata.getPrimitiveValue(); - dirtyMetadata.put(EntityDataTypes.VARIANT, switch (variant) { - case 6, 7, 8 -> variant - 1; // dark_oak, mangrove, bamboo - case 5 -> 8; // cherry - default -> variant; - }); - } - public void setPaddlingLeft(BooleanEntityMetadata entityMetadata) { isPaddlingLeft = entityMetadata.getPrimitiveValue(); if (!isPaddlingLeft) { @@ -187,6 +183,12 @@ public class BoatEntity extends Entity implements Leashable, Tickable { @Override public void tick() { // Java sends simply "true" and "false" (is_paddling_left), Bedrock keeps sending packets as you're rowing + if (session.getPlayerEntity().getVehicle() == this) { + // For packet timing accuracy, we'll send the packets here, as that's what Java Edition 1.21.3 does. + ServerboundPaddleBoatPacket steerPacket = new ServerboundPaddleBoatPacket(session.isSteeringLeft(), session.isSteeringRight()); + session.sendDownstreamGamePacket(steerPacket); + return; + } doTick = !doTick; // Run every 100 ms if (!doTick || passengers.isEmpty()) { return; @@ -212,6 +214,10 @@ public class BoatEntity extends Entity implements Leashable, Tickable { return leashHolderBedrockId; } + public Item getPickItem() { + return variant.pickItem; + } + private void sendAnimationPacket(GeyserSession session, Entity rower, AnimatePacket.Action action, float rowTime) { AnimatePacket packet = new AnimatePacket(); packet.setRuntimeEntityId(rower.getGeyserId()); @@ -219,4 +225,27 @@ public class BoatEntity extends Entity implements Leashable, Tickable { packet.setRowingTime(rowTime); session.sendUpstreamPacket(packet); } + + /** + * Ordered by Bedrock ordinal + */ + public enum BoatVariant { + OAK(Items.OAK_BOAT, Items.OAK_CHEST_BOAT), + SPRUCE(Items.SPRUCE_BOAT, Items.SPRUCE_CHEST_BOAT), + BIRCH(Items.BIRCH_BOAT, Items.BIRCH_CHEST_BOAT), + JUNGLE(Items.JUNGLE_BOAT, Items.JUNGLE_CHEST_BOAT), + ACACIA(Items.ACACIA_BOAT, Items.ACACIA_CHEST_BOAT), + DARK_OAK(Items.DARK_OAK_BOAT, Items.DARK_OAK_CHEST_BOAT), + MANGROVE(Items.MANGROVE_BOAT, Items.MANGROVE_CHEST_BOAT), + BAMBOO(Items.BAMBOO_RAFT, Items.BAMBOO_CHEST_RAFT), + CHERRY(Items.CHERRY_BOAT, Items.CHERRY_CHEST_BOAT); + + private final Item pickItem; + final Item chestPickItem; + + BoatVariant(Item pickItem, Item chestPickItem) { + this.pickItem = pickItem; + this.chestPickItem = chestPickItem; + } + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ChestBoatEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ChestBoatEntity.java index 479b4d80d..967da41df 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ChestBoatEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ChestBoatEntity.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.entity.type; import org.cloudburstmc.math.vector.Vector3f; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; @@ -35,8 +36,8 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.UUID; public class ChestBoatEntity extends BoatEntity { - public ChestBoatEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { - super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); + public ChestBoatEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, BoatVariant variant) { + super(session, entityId, geyserId, uuid, definition, position, motion, yaw, variant); } @Override @@ -48,4 +49,9 @@ public class ChestBoatEntity extends BoatEntity { public InteractionResult interact(Hand hand) { return passengers.isEmpty() && !session.isSneaking() ? super.interact(hand) : InteractionResult.SUCCESS; } + + @Override + public Item getPickItem() { + return this.variant.chestPickItem; + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java b/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java index a016916f0..0d3214709 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java @@ -25,12 +25,6 @@ package org.geysermc.geyser.entity.type; -import java.util.Collections; -import java.util.EnumSet; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.UUID; import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; @@ -67,6 +61,13 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEnt import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; +import java.util.Collections; +import java.util.EnumSet; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; + @Getter @Setter public class Entity implements GeyserEntity { @@ -89,6 +90,7 @@ public class Entity implements GeyserEntity { /** * x = Yaw, y = Pitch, z = HeadYaw + * Java: Y = Yaw, X = Pitch */ protected float yaw; protected float pitch; @@ -699,9 +701,4 @@ public class Entity implements GeyserEntity { packet.setData(data); session.sendUpstreamPacket(packet); } - - @SuppressWarnings("unchecked") - public @Nullable I as(Class entityClass) { - return entityClass.isInstance(this) ? (I) this : null; - } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/LivingEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/LivingEntity.java index 626ceca5c..33064edfe 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/LivingEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/LivingEntity.java @@ -25,11 +25,6 @@ package org.geysermc.geyser.entity.type; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.UUID; import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; @@ -71,6 +66,12 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.particle.EntityEffect import org.geysermc.mcprotocollib.protocol.data.game.level.particle.Particle; import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ParticleType; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + @Getter @Setter public class LivingEntity extends Entity { @@ -445,35 +446,35 @@ public class LivingEntity extends Entity { protected void updateAttribute(Attribute javaAttribute, List newAttributes) { if (javaAttribute.getType() instanceof AttributeType.Builtin type) { switch (type) { - case GENERIC_MAX_HEALTH -> { + case MAX_HEALTH -> { // Since 1.18.0, setting the max health to 0 or below causes the entity to die on Bedrock but not on Java // See https://github.com/GeyserMC/Geyser/issues/2971 this.maxHealth = Math.max((float) AttributeUtils.calculateValue(javaAttribute), 1f); newAttributes.add(createHealthAttribute()); } - case GENERIC_MOVEMENT_SPEED -> { + case MOVEMENT_SPEED -> { AttributeData attributeData = calculateAttribute(javaAttribute, GeyserAttributeType.MOVEMENT_SPEED); newAttributes.add(attributeData); if (this instanceof ClientVehicle clientVehicle) { clientVehicle.getVehicleComponent().setMoveSpeed(attributeData.getValue()); } } - case GENERIC_STEP_HEIGHT -> { + case STEP_HEIGHT -> { if (this instanceof ClientVehicle clientVehicle) { clientVehicle.getVehicleComponent().setStepHeight((float) AttributeUtils.calculateValue(javaAttribute)); } } - case GENERIC_GRAVITY -> { + case GRAVITY -> { if (this instanceof ClientVehicle clientVehicle) { clientVehicle.getVehicleComponent().setGravity(AttributeUtils.calculateValue(javaAttribute)); } } - case GENERIC_ATTACK_DAMAGE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.ATTACK_DAMAGE)); - case GENERIC_FLYING_SPEED -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.FLYING_SPEED)); - case GENERIC_FOLLOW_RANGE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.FOLLOW_RANGE)); - case GENERIC_KNOCKBACK_RESISTANCE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.KNOCKBACK_RESISTANCE)); - case GENERIC_JUMP_STRENGTH -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.HORSE_JUMP_STRENGTH)); - case GENERIC_SCALE -> { + case ATTACK_DAMAGE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.ATTACK_DAMAGE)); + case FLYING_SPEED -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.FLYING_SPEED)); + case FOLLOW_RANGE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.FOLLOW_RANGE)); + case KNOCKBACK_RESISTANCE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.KNOCKBACK_RESISTANCE)); + case JUMP_STRENGTH -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.HORSE_JUMP_STRENGTH)); + case SCALE -> { // Attribute on Java, entity data on Bedrock setAttributeScale((float) AttributeUtils.calculateValue(javaAttribute)); updateBedrockMetadata(); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/AgeableWaterEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/AgeableWaterEntity.java new file mode 100644 index 000000000..843215674 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/AgeableWaterEntity.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.entity.type.living; + +import org.cloudburstmc.math.vector.Vector3f; +import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.session.GeyserSession; + +import java.util.UUID; + +public abstract class AgeableWaterEntity extends AgeableEntity { + public AgeableWaterEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); + } + + @Override + public boolean canBeLeashed() { + return false; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/DolphinEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/DolphinEntity.java index a0ea79d67..8c404be97 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/DolphinEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/DolphinEntity.java @@ -37,7 +37,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import java.util.UUID; -public class DolphinEntity extends WaterEntity { +public class DolphinEntity extends AgeableWaterEntity { public DolphinEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/SquidEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/SquidEntity.java index 6285bd9a4..ac3456829 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/SquidEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/SquidEntity.java @@ -36,7 +36,7 @@ import org.geysermc.geyser.session.GeyserSession; import java.util.UUID; import java.util.concurrent.CompletableFuture; -public class SquidEntity extends WaterEntity implements Tickable { +public class SquidEntity extends AgeableWaterEntity implements Tickable { private float targetPitch; private float targetYaw; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/AnimalEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/AnimalEntity.java index 2e627b461..57cbdc783 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/AnimalEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/AnimalEntity.java @@ -33,8 +33,9 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.type.living.AgeableEntity; import org.geysermc.geyser.inventory.GeyserItemStack; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; @@ -48,7 +49,7 @@ public abstract class AnimalEntity extends AgeableEntity { } protected final boolean canEat(GeyserItemStack itemStack) { - ItemTag tag = getFoodTag(); + Tag tag = getFoodTag(); if (tag == null) { return false; } @@ -58,7 +59,7 @@ public abstract class AnimalEntity extends AgeableEntity { /** * @return the tag associated with this animal for eating food. Null for nothing or different behavior. */ - protected abstract @Nullable ItemTag getFoodTag(); + protected abstract @Nullable Tag getFoodTag(); @NonNull @Override diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/ArmadilloEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/ArmadilloEntity.java index 968520bb6..2b443f5e4 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/ArmadilloEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/ArmadilloEntity.java @@ -28,8 +28,10 @@ package org.geysermc.geyser.entity.type.living.animal; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.ArmadilloState; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata; @@ -75,7 +77,7 @@ public class ArmadilloEntity extends AnimalEntity { @Override @Nullable - protected ItemTag getFoodTag() { + protected Tag getFoodTag() { return ItemTag.ARMADILLO_FOOD; } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/AxolotlEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/AxolotlEntity.java index a0ab56ead..0a87f59bc 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/AxolotlEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/AxolotlEntity.java @@ -32,8 +32,10 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.GeyserItemStack; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.geyser.util.EntityUtils; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; @@ -62,7 +64,7 @@ public class AxolotlEntity extends AnimalEntity { @Override @Nullable - protected ItemTag getFoodTag() { + protected Tag getFoodTag() { return ItemTag.AXOLOTL_FOOD; } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/BeeEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/BeeEntity.java index 4fcf0e178..5f8956b6a 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/BeeEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/BeeEntity.java @@ -32,8 +32,10 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; @@ -69,7 +71,7 @@ public class BeeEntity extends AnimalEntity { @Override @Nullable - protected ItemTag getFoodTag() { + protected Tag getFoodTag() { return ItemTag.BEE_FOOD; } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/ChickenEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/ChickenEntity.java index 075a49923..0c8e437c8 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/ChickenEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/ChickenEntity.java @@ -28,8 +28,10 @@ package org.geysermc.geyser.entity.type.living.animal; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.session.cache.tags.Tag; import java.util.UUID; @@ -41,7 +43,7 @@ public class ChickenEntity extends AnimalEntity { @Override @Nullable - protected ItemTag getFoodTag() { + protected Tag getFoodTag() { return ItemTag.CHICKEN_FOOD; } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/CowEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/CowEntity.java index 64e7de193..66210068b 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/CowEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/CowEntity.java @@ -33,8 +33,10 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; @@ -69,7 +71,7 @@ public class CowEntity extends AnimalEntity { @Override @Nullable - protected ItemTag getFoodTag() { + protected Tag getFoodTag() { return ItemTag.COW_FOOD; } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/FoxEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/FoxEntity.java index e20031baa..b140b7956 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/FoxEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/FoxEntity.java @@ -30,8 +30,10 @@ import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; @@ -57,7 +59,7 @@ public class FoxEntity extends AnimalEntity { @Override @Nullable - protected ItemTag getFoodTag() { + protected Tag getFoodTag() { return ItemTag.FOX_FOOD; } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/FrogEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/FrogEntity.java index 120bfcdd4..a0b909b75 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/FrogEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/FrogEntity.java @@ -31,8 +31,10 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.type.Entity; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata; @@ -77,7 +79,7 @@ public class FrogEntity extends AnimalEntity { @Override @Nullable - protected ItemTag getFoodTag() { + protected Tag getFoodTag() { return ItemTag.FROG_FOOD; } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/GoatEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/GoatEntity.java index 4e919b81c..b5e4ad117 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/GoatEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/GoatEntity.java @@ -34,8 +34,10 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; @@ -99,7 +101,7 @@ public class GoatEntity extends AnimalEntity { @Override @Nullable - protected ItemTag getFoodTag() { + protected Tag getFoodTag() { return ItemTag.GOAT_FOOD; } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/HoglinEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/HoglinEntity.java index cc23fc607..b506f1425 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/HoglinEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/HoglinEntity.java @@ -30,8 +30,10 @@ import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import java.util.UUID; @@ -58,7 +60,7 @@ public class HoglinEntity extends AnimalEntity { @Override @Nullable - protected ItemTag getFoodTag() { + protected Tag getFoodTag() { return ItemTag.HOGLIN_FOOD; } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/OcelotEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/OcelotEntity.java index 9d6d33227..c45092b02 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/OcelotEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/OcelotEntity.java @@ -31,8 +31,10 @@ import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.GeyserItemStack; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; @@ -47,7 +49,7 @@ public class OcelotEntity extends AnimalEntity { @Override @Nullable - protected ItemTag getFoodTag() { + protected Tag getFoodTag() { return ItemTag.OCELOT_FOOD; } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PandaEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PandaEntity.java index aaa7c2d7e..022e58bc0 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PandaEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PandaEntity.java @@ -34,8 +34,10 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.GeyserItemStack; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; @@ -90,7 +92,7 @@ public class PandaEntity extends AnimalEntity { @Override @Nullable - protected ItemTag getFoodTag() { + protected Tag getFoodTag() { return ItemTag.PANDA_FOOD; } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PigEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PigEntity.java index 2ec23d673..b8ba2c94f 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PigEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PigEntity.java @@ -38,9 +38,11 @@ import org.geysermc.geyser.entity.vehicle.BoostableVehicleComponent; import org.geysermc.geyser.entity.vehicle.ClientVehicle; import org.geysermc.geyser.entity.vehicle.VehicleComponent; import org.geysermc.geyser.inventory.GeyserItemStack; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.geyser.util.EntityUtils; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; @@ -58,7 +60,7 @@ public class PigEntity extends AnimalEntity implements Tickable, ClientVehicle { @Override @Nullable - protected ItemTag getFoodTag() { + protected Tag getFoodTag() { return ItemTag.PIG_FOOD; } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PolarBearEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PolarBearEntity.java index 0e83615f7..900878dbd 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PolarBearEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PolarBearEntity.java @@ -28,8 +28,9 @@ package org.geysermc.geyser.entity.type.living.animal; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.session.cache.tags.Tag; import java.util.UUID; @@ -41,7 +42,7 @@ public class PolarBearEntity extends AnimalEntity { @Override @Nullable - protected ItemTag getFoodTag() { + protected Tag getFoodTag() { return null; } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/RabbitEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/RabbitEntity.java index fbfc5d40a..dca6fe5ff 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/RabbitEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/RabbitEntity.java @@ -31,8 +31,10 @@ import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.geyser.util.EntityUtils; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; @@ -79,7 +81,7 @@ public class RabbitEntity extends AnimalEntity { @Override @Nullable - protected ItemTag getFoodTag() { + protected Tag getFoodTag() { return ItemTag.RABBIT_FOOD; } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/SheepEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/SheepEntity.java index 155ddf00c..e26b0be61 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/SheepEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/SheepEntity.java @@ -34,8 +34,10 @@ import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.DyeItem; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; @@ -59,7 +61,7 @@ public class SheepEntity extends AnimalEntity { @Override @Nullable - protected ItemTag getFoodTag() { + protected Tag getFoodTag() { return ItemTag.SHEEP_FOOD; } @@ -103,4 +105,4 @@ public class SheepEntity extends AnimalEntity { private boolean canDye(GeyserItemStack item) { return item.asItem() instanceof DyeItem dyeItem && dyeItem.dyeColor() != this.color && !getFlag(EntityFlag.SHEARED); } -} \ No newline at end of file +} diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/SnifferEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/SnifferEntity.java index 11fee5bbf..203a48f19 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/SnifferEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/SnifferEntity.java @@ -35,8 +35,10 @@ import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.Tickable; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.SnifferState; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata; @@ -73,7 +75,7 @@ public class SnifferEntity extends AnimalEntity implements Tickable { @Override @Nullable - protected ItemTag getFoodTag() { + protected Tag getFoodTag() { return ItemTag.SNIFFER_FOOD; } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/StriderEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/StriderEntity.java index e06af2786..62318e255 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/StriderEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/StriderEntity.java @@ -39,9 +39,11 @@ import org.geysermc.geyser.entity.vehicle.BoostableVehicleComponent; import org.geysermc.geyser.entity.vehicle.ClientVehicle; import org.geysermc.geyser.entity.vehicle.VehicleComponent; import org.geysermc.geyser.inventory.GeyserItemStack; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.geyser.util.EntityUtils; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; @@ -105,7 +107,7 @@ public class StriderEntity extends AnimalEntity implements Tickable, ClientVehic @Override @Nullable - protected ItemTag getFoodTag() { + protected Tag getFoodTag() { return ItemTag.STRIDER_FOOD; } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/TurtleEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/TurtleEntity.java index ae7f2d2bd..1f700f12b 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/TurtleEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/TurtleEntity.java @@ -29,8 +29,10 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import java.util.UUID; @@ -51,7 +53,7 @@ public class TurtleEntity extends AnimalEntity { @Override @Nullable - protected ItemTag getFoodTag() { + protected Tag getFoodTag() { return ItemTag.TURTLE_FOOD; } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/AbstractHorseEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/AbstractHorseEntity.java index ddc212053..100a29299 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/AbstractHorseEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/AbstractHorseEntity.java @@ -39,8 +39,10 @@ import org.geysermc.geyser.entity.attribute.GeyserAttributeType; import org.geysermc.geyser.entity.type.living.animal.AnimalEntity; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; @@ -119,7 +121,7 @@ public class AbstractHorseEntity extends AnimalEntity { @Override @Nullable - protected ItemTag getFoodTag() { + protected Tag getFoodTag() { return ItemTag.HORSE_FOOD; } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/CamelEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/CamelEntity.java index 3c0bf1a70..ca39bd1e6 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/CamelEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/CamelEntity.java @@ -35,12 +35,14 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType; import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.entity.attribute.GeyserAttributeType; import org.geysermc.geyser.entity.vehicle.CamelVehicleComponent; import org.geysermc.geyser.entity.vehicle.ClientVehicle; import org.geysermc.geyser.entity.vehicle.VehicleComponent; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.Attribute; import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.AttributeType; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose; @@ -100,7 +102,7 @@ public class CamelEntity extends AbstractHorseEntity implements ClientVehicle { } @Override - protected @Nullable ItemTag getFoodTag() { + protected @Nullable Tag getFoodTag() { return ItemTag.CAMEL_FOOD; } @@ -141,7 +143,7 @@ public class CamelEntity extends AbstractHorseEntity implements ClientVehicle { @Override protected AttributeData calculateAttribute(Attribute javaAttribute, GeyserAttributeType type) { AttributeData attributeData = super.calculateAttribute(javaAttribute, type); - if (javaAttribute.getType() == AttributeType.Builtin.GENERIC_JUMP_STRENGTH) { + if (javaAttribute.getType() == AttributeType.Builtin.JUMP_STRENGTH) { vehicleComponent.setHorseJumpStrength(attributeData.getValue()); } return attributeData; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/LlamaEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/LlamaEntity.java index 76939ceb9..d27a1fff3 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/LlamaEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/LlamaEntity.java @@ -30,8 +30,10 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.geyser.util.MathUtils; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; @@ -56,7 +58,7 @@ public class LlamaEntity extends ChestedHorseEntity { } @Override - protected @Nullable ItemTag getFoodTag() { + protected @Nullable Tag getFoodTag() { return ItemTag.LLAMA_FOOD; } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/CatEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/CatEntity.java index bf1555e9d..fb53c18ed 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/CatEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/CatEntity.java @@ -32,8 +32,10 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.GeyserItemStack; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; @@ -109,7 +111,7 @@ public class CatEntity extends TameableEntity { } @Override - protected @Nullable ItemTag getFoodTag() { + protected @Nullable Tag getFoodTag() { return ItemTag.CAT_FOOD; } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/ParrotEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/ParrotEntity.java index 69b19b1b9..95e9c901b 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/ParrotEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/ParrotEntity.java @@ -34,6 +34,7 @@ import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; @@ -47,7 +48,7 @@ public class ParrotEntity extends TameableEntity { @Override @Nullable - protected ItemTag getFoodTag() { + protected Tag getFoodTag() { return null; } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/WolfEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/WolfEntity.java index e7fde2be8..f0b554ef9 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/WolfEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/WolfEntity.java @@ -36,8 +36,10 @@ import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.enchantment.EnchantmentComponent; import org.geysermc.geyser.item.type.DyeItem; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.geyser.util.ItemUtils; @@ -116,7 +118,7 @@ public class WolfEntity extends TameableEntity { @Override @Nullable - protected ItemTag getFoodTag() { + protected Tag getFoodTag() { return ItemTag.WOLF_FOOD; } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java index 2abc34d2b..7e747e33d 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java @@ -25,12 +25,6 @@ package org.geysermc.geyser.entity.type.player; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.UUID; -import java.util.concurrent.TimeUnit; import lombok.Getter; import lombok.Setter; import net.kyori.adventure.text.Component; @@ -65,6 +59,13 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.Boolea import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + @Getter @Setter public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { public static final float SNEAKING_POSE_HEIGHT = 1.5f; @@ -250,10 +251,6 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { } } - public void updateRotation(float yaw, float pitch, float headYaw, boolean isOnGround) { - moveRelative(0, 0, 0, yaw, pitch, headYaw, isOnGround); - } - @Override public void setPosition(Vector3f position) { if (this.bedPosition != null) { diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java index f427b001a..9d5bc011c 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java @@ -38,8 +38,8 @@ import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket; import org.geysermc.geyser.entity.attribute.GeyserAttributeType; import org.geysermc.geyser.item.Items; -import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.level.BedrockDimension; +import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.AttributeUtils; import org.geysermc.geyser.util.DimensionUtils; @@ -143,9 +143,32 @@ public class SessionPlayerEntity extends PlayerEntity { this.position = position.add(0, definition.offset(), 0); } + /** + * Special method used only when updating the session player's rotation. + * For some reason, Mode#NORMAL ignored rotation. Yay. + * @param yaw the new yaw + * @param pitch the new pitch + * @param headYaw the head yaw + */ + public void updateOwnRotation(float yaw, float pitch, float headYaw) { + setYaw(yaw); + setPitch(pitch); + setHeadYaw(headYaw); + + MovePlayerPacket movePlayerPacket = new MovePlayerPacket(); + movePlayerPacket.setRuntimeEntityId(geyserId); + movePlayerPacket.setPosition(position); + movePlayerPacket.setRotation(getBedrockRotation()); + movePlayerPacket.setOnGround(isOnGround()); + movePlayerPacket.setMode(MovePlayerPacket.Mode.TELEPORT); + movePlayerPacket.setTeleportationCause(MovePlayerPacket.TeleportationCause.BEHAVIOR); + + session.sendUpstreamPacket(movePlayerPacket); + } + /** * Set the player's position without applying an offset or moving the bounding box - * This is used in BedrockMovePlayerTranslator which receives the player's position + * This is used in BedrockMovePlayer which receives the player's position * with the offset pre-applied * * @param position the new position of the Bedrock player @@ -247,9 +270,9 @@ public class SessionPlayerEntity extends PlayerEntity { @Override protected void updateAttribute(Attribute javaAttribute, List newAttributes) { - if (javaAttribute.getType() == AttributeType.Builtin.GENERIC_ATTACK_SPEED) { + if (javaAttribute.getType() == AttributeType.Builtin.ATTACK_SPEED) { session.setAttackSpeed(AttributeUtils.calculateValue(javaAttribute)); - } else if (javaAttribute.getType() == AttributeType.Builtin.PLAYER_BLOCK_INTERACTION_RANGE) { + } else if (javaAttribute.getType() == AttributeType.Builtin.BLOCK_INTERACTION_RANGE) { this.blockInteractionRange = AttributeUtils.calculateValue(javaAttribute); } else { super.updateAttribute(javaAttribute, newAttributes); diff --git a/core/src/main/java/org/geysermc/geyser/entity/vehicle/VehicleComponent.java b/core/src/main/java/org/geysermc/geyser/entity/vehicle/VehicleComponent.java index db703a3cb..91f54162b 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/vehicle/VehicleComponent.java +++ b/core/src/main/java/org/geysermc/geyser/entity/vehicle/VehicleComponent.java @@ -76,8 +76,8 @@ public class VehicleComponent { public VehicleComponent(T vehicle, float stepHeight) { this.vehicle = vehicle; this.stepHeight = stepHeight; - this.moveSpeed = (float) AttributeType.Builtin.GENERIC_MOVEMENT_SPEED.getDef(); - this.gravity = AttributeType.Builtin.GENERIC_GRAVITY.getDef(); + this.moveSpeed = (float) AttributeType.Builtin.MOVEMENT_SPEED.getDef(); + this.gravity = AttributeType.Builtin.GRAVITY.getDef(); double width = vehicle.getBoundingBoxWidth(); double height = vehicle.getBoundingBoxHeight(); @@ -758,7 +758,6 @@ public class VehicleComponent { ServerboundMoveVehiclePacket moveVehiclePacket = new ServerboundMoveVehiclePacket(javaPos.getX(), javaPos.getY(), javaPos.getZ(), rotation.getX(), rotation.getY()); vehicle.getSession().sendDownstreamPacket(moveVehiclePacket); - vehicle.getSession().setLastVehicleMoveTimestamp(System.currentTimeMillis()); } protected double getGravity() { diff --git a/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java b/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java index 744ad70b6..256de7799 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java @@ -29,6 +29,7 @@ import lombok.*; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; +import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.registry.Registries; @@ -38,6 +39,10 @@ import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.EmptySlotDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.ItemSlotDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.ItemStackSlotDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.SlotDisplay; import java.util.HashMap; @@ -77,6 +82,20 @@ public class GeyserItemStack { return itemStack == null ? EMPTY : new GeyserItemStack(itemStack.getId(), itemStack.getAmount(), itemStack.getDataComponents()); } + public static @NonNull GeyserItemStack from(@NonNull SlotDisplay slotDisplay) { + if (slotDisplay instanceof EmptySlotDisplay) { + return GeyserItemStack.EMPTY; + } + if (slotDisplay instanceof ItemSlotDisplay itemSlotDisplay) { + return GeyserItemStack.of(itemSlotDisplay.item(), 1); + } + if (slotDisplay instanceof ItemStackSlotDisplay itemStackSlotDisplay) { + return GeyserItemStack.from(itemStackSlotDisplay.itemStack()); + } + GeyserImpl.getInstance().getLogger().warning("Unsure how to convert to ItemStack: " + slotDisplay); + return GeyserItemStack.EMPTY; + } + public int getJavaId() { return isEmpty() ? 0 : javaId; } @@ -163,7 +182,17 @@ public class GeyserItemStack { return session.getItemMappings().getMapping(this.javaId); } + public SlotDisplay asSlotDisplay() { + if (isEmpty()) { + return EmptySlotDisplay.INSTANCE; + } + return new ItemStackSlotDisplay(this.getItemStack()); + } + public Item asItem() { + if (isEmpty()) { + return Items.AIR; + } if (item == null) { return (item = Registries.JAVA_ITEMS.get().get(javaId)); } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/GeyserInstrument.java b/core/src/main/java/org/geysermc/geyser/inventory/item/GeyserInstrument.java new file mode 100644 index 000000000..9983a8e90 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/inventory/item/GeyserInstrument.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2024 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.inventory.item; + +import net.kyori.adventure.key.Key; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.cloudburstmc.nbt.NbtMap; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.registry.JavaRegistry; +import org.geysermc.geyser.session.cache.registry.RegistryEntryContext; +import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.geyser.util.MinecraftKey; +import org.geysermc.geyser.util.SoundUtils; +import org.geysermc.mcprotocollib.protocol.data.game.Holder; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.Instrument; +import org.geysermc.mcprotocollib.protocol.data.game.level.sound.BuiltinSound; + +import java.util.Locale; + +public interface GeyserInstrument { + + static GeyserInstrument read(RegistryEntryContext context) { + NbtMap data = context.data(); + String soundEvent = SoundUtils.readSoundEvent(data, "instrument " + context.id()); + float range = data.getFloat("range"); + String description = MessageTranslator.deserializeDescriptionForTooltip(context.session(), data); + BedrockInstrument bedrockInstrument = BedrockInstrument.getByJavaIdentifier(context.id()); + return new GeyserInstrument.Impl(soundEvent, range, description, bedrockInstrument); + } + + String soundEvent(); + + float range(); + + /** + * In Bedrock format + */ + String description(); + + BedrockInstrument bedrockInstrument(); + + /** + * @return the ID of the Bedrock counterpart for this instrument. If there is none ({@link #bedrockInstrument()} is null), then -1 is returned. + */ + default int bedrockId() { + BedrockInstrument bedrockInstrument = bedrockInstrument(); + if (bedrockInstrument != null) { + return bedrockInstrument.ordinal(); + } + return -1; + } + + /** + * @return the ID of the Java counterpart for the given Bedrock ID. If an invalid Bedrock ID was given, or there is no counterpart, -1 is returned. + */ + static int bedrockIdToJava(GeyserSession session, int id) { + JavaRegistry instruments = session.getRegistryCache().instruments(); + BedrockInstrument bedrockInstrument = BedrockInstrument.getByBedrockId(id); + if (bedrockInstrument != null) { + for (int i = 0; i < instruments.values().size(); i++) { + GeyserInstrument instrument = instruments.byId(i); + if (instrument.bedrockInstrument() == bedrockInstrument) { + return i; + } + } + } + return -1; + } + + static GeyserInstrument fromHolder(GeyserSession session, Holder holder) { + if (holder.isId()) { + return session.getRegistryCache().instruments().byId(holder.id()); + } + Instrument custom = holder.custom(); + return new Wrapper(custom, session.locale()); + } + + record Wrapper(Instrument instrument, String locale) implements GeyserInstrument { + @Override + public String soundEvent() { + return instrument.getSoundEvent().getName(); + } + + @Override + public float range() { + return instrument.getRange(); + } + + @Override + public String description() { + return MessageTranslator.convertMessageForTooltip(instrument.getDescription(), locale); + } + + @Override + public BedrockInstrument bedrockInstrument() { + if (instrument.getSoundEvent() instanceof BuiltinSound) { + return BedrockInstrument.getByJavaIdentifier(MinecraftKey.key(instrument.getSoundEvent().getName())); + } + // Probably custom + return null; + } + } + + record Impl(String soundEvent, float range, String description, @Nullable BedrockInstrument bedrockInstrument) implements GeyserInstrument { + } + + /** + * Each vanilla instrument on Bedrock, ordered in their network IDs. + */ + enum BedrockInstrument { + PONDER, + SING, + SEEK, + FEEL, + ADMIRE, + CALL, + YEARN, + DREAM; + + private static final BedrockInstrument[] VALUES = values(); + private final Key javaIdentifier; + + BedrockInstrument() { + this.javaIdentifier = MinecraftKey.key(this.name().toLowerCase(Locale.ENGLISH) + "_goat_horn"); + } + + public static @Nullable BedrockInstrument getByJavaIdentifier(Key javaIdentifier) { + for (BedrockInstrument instrument : VALUES) { + if (instrument.javaIdentifier.equals(javaIdentifier)) { + return instrument; + } + } + return null; + } + + public static @Nullable BedrockInstrument getByBedrockId(int bedrockId) { + if (bedrockId >= 0 && bedrockId < VALUES.length) { + return VALUES[bedrockId]; + } + return null; + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/Potion.java b/core/src/main/java/org/geysermc/geyser/inventory/item/Potion.java index 129c365a9..21de6394e 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/item/Potion.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/item/Potion.java @@ -99,7 +99,7 @@ public enum Potion { } public PotionContents toComponent() { - return new PotionContents(this.ordinal(), -1, Collections.emptyList()); + return new PotionContents(this.ordinal(), -1, Collections.emptyList(), null); } public static Potion getByJavaIdentifier(String javaIdentifier) { diff --git a/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserRecipe.java b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserRecipe.java index 8b7fa9522..7d25c5803 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserRecipe.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserRecipe.java @@ -25,11 +25,10 @@ package org.geysermc.geyser.inventory.recipe; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.SlotDisplay; /** - * A more compact version of {@link org.geysermc.mcprotocollib.protocol.data.game.recipe.Recipe}. + * A more compact version of {@link org.geysermc.mcprotocollib.protocol.data.game.recipe.display.RecipeDisplay}. */ public interface GeyserRecipe { /** @@ -37,6 +36,5 @@ public interface GeyserRecipe { */ boolean isShaped(); - @Nullable - ItemStack result(); + SlotDisplay result(); } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapedRecipe.java b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapedRecipe.java index ac9fa3ab4..7fc1d52aa 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapedRecipe.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapedRecipe.java @@ -25,15 +25,15 @@ package org.geysermc.geyser.inventory.recipe; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; -import org.geysermc.mcprotocollib.protocol.data.game.recipe.Ingredient; -import org.geysermc.mcprotocollib.protocol.data.game.recipe.data.ShapedRecipeData; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.ShapedCraftingRecipeDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.SlotDisplay; -public record GeyserShapedRecipe(int width, int height, Ingredient[] ingredients, @Nullable ItemStack result) implements GeyserRecipe { +import java.util.List; - public GeyserShapedRecipe(ShapedRecipeData data) { - this(data.getWidth(), data.getHeight(), data.getIngredients(), data.getResult()); +public record GeyserShapedRecipe(int width, int height, List ingredients, SlotDisplay result) implements GeyserRecipe { + + public GeyserShapedRecipe(ShapedCraftingRecipeDisplay data) { + this(data.width(), data.height(), data.ingredients(), data.result()); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapelessRecipe.java b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapelessRecipe.java index 388831d4c..ed513a804 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapelessRecipe.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapelessRecipe.java @@ -25,15 +25,15 @@ package org.geysermc.geyser.inventory.recipe; -import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; -import org.geysermc.mcprotocollib.protocol.data.game.recipe.Ingredient; -import org.geysermc.mcprotocollib.protocol.data.game.recipe.data.ShapelessRecipeData; -import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.ShapelessCraftingRecipeDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.SlotDisplay; -public record GeyserShapelessRecipe(Ingredient[] ingredients, @Nullable ItemStack result) implements GeyserRecipe { +import java.util.List; - public GeyserShapelessRecipe(ShapelessRecipeData data) { - this(data.getIngredients(), data.getResult()); +public record GeyserShapelessRecipe(List ingredients, SlotDisplay result) implements GeyserRecipe { + + public GeyserShapelessRecipe(ShapelessCraftingRecipeDisplay data) { + this(data.ingredients(), data.result()); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserSmithingRecipe.java b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserSmithingRecipe.java new file mode 100644 index 000000000..7e4131a4c --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserSmithingRecipe.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.inventory.recipe; + +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.SmithingRecipeDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.SlotDisplay; + +public record GeyserSmithingRecipe(SlotDisplay template, + SlotDisplay base, + SlotDisplay addition, + SlotDisplay result) implements GeyserRecipe { + public GeyserSmithingRecipe(SmithingRecipeDisplay display) { + this(display.template(), display.base(), display.addition(), display.result()); + } + + @Override + public boolean isShaped() { + return false; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/AnvilInventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/AnvilInventoryUpdater.java index dc532cc62..0ffb74082 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/AnvilInventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/AnvilInventoryUpdater.java @@ -41,17 +41,15 @@ import org.geysermc.geyser.inventory.item.BedrockEnchantment; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.enchantment.Enchantment; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.session.cache.tags.EnchantmentTag; -import org.geysermc.geyser.session.cache.tags.ItemTag; import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.ItemUtils; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemEnchantments; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundRenameItemPacket; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.IntStream; @@ -314,14 +312,10 @@ public class AnvilInventoryUpdater extends InventoryUpdater { for (Object2IntMap.Entry entry : getEnchantments(session, material).object2IntEntrySet()) { Enchantment enchantment = entry.getKey(); - HolderSet supportedItems = enchantment.supportedItems(); - int[] supportedItemIds = supportedItems.resolve(tagId -> session.getTagCache().get(ItemTag.ALL_ITEM_TAGS.get(tagId))); - boolean canApply = isEnchantedBook(input) || IntStream.of(supportedItemIds).anyMatch(id -> id == input.getJavaId()); + boolean canApply = isEnchantedBook(input) || session.getTagCache().is(enchantment.supportedItems(), input.asItem()); - HolderSet exclusiveSet = enchantment.exclusiveSet(); - int[] incompatibleEnchantments = exclusiveSet.resolve(tagId -> session.getTagCache().get(EnchantmentTag.ALL_ENCHANTMENT_TAGS.get(tagId))); - for (int i : incompatibleEnchantments) { - Enchantment incompatible = session.getRegistryCache().enchantments().byId(i); + List incompatibleEnchantments = enchantment.exclusiveSet().resolve(session); + for (Enchantment incompatible : incompatibleEnchantments) { if (combinedEnchantments.containsKey(incompatible)) { canApply = false; if (!bedrock) { diff --git a/core/src/main/java/org/geysermc/geyser/item/Items.java b/core/src/main/java/org/geysermc/geyser/item/Items.java index 462e98d19..302fdf99c 100644 --- a/core/src/main/java/org/geysermc/geyser/item/Items.java +++ b/core/src/main/java/org/geysermc/geyser/item/Items.java @@ -25,9 +25,39 @@ package org.geysermc.geyser.item; -import org.geysermc.geyser.item.components.Rarity; import org.geysermc.geyser.item.components.ToolTier; -import org.geysermc.geyser.item.type.*; +import org.geysermc.geyser.item.type.ArmorItem; +import org.geysermc.geyser.item.type.ArrowItem; +import org.geysermc.geyser.item.type.AxolotlBucketItem; +import org.geysermc.geyser.item.type.BannerItem; +import org.geysermc.geyser.item.type.BlockItem; +import org.geysermc.geyser.item.type.BoatItem; +import org.geysermc.geyser.item.type.CompassItem; +import org.geysermc.geyser.item.type.CrossbowItem; +import org.geysermc.geyser.item.type.DecoratedPotItem; +import org.geysermc.geyser.item.type.DyeItem; +import org.geysermc.geyser.item.type.DyeableArmorItem; +import org.geysermc.geyser.item.type.ElytraItem; +import org.geysermc.geyser.item.type.EnchantedBookItem; +import org.geysermc.geyser.item.type.FilledMapItem; +import org.geysermc.geyser.item.type.FireworkRocketItem; +import org.geysermc.geyser.item.type.FireworkStarItem; +import org.geysermc.geyser.item.type.FishingRodItem; +import org.geysermc.geyser.item.type.GoatHornItem; +import org.geysermc.geyser.item.type.Item; +import org.geysermc.geyser.item.type.MaceItem; +import org.geysermc.geyser.item.type.MapItem; +import org.geysermc.geyser.item.type.PlayerHeadItem; +import org.geysermc.geyser.item.type.PotionItem; +import org.geysermc.geyser.item.type.ShieldItem; +import org.geysermc.geyser.item.type.ShulkerBoxItem; +import org.geysermc.geyser.item.type.SpawnEggItem; +import org.geysermc.geyser.item.type.TieredItem; +import org.geysermc.geyser.item.type.TippedArrowItem; +import org.geysermc.geyser.item.type.TropicalFishBucketItem; +import org.geysermc.geyser.item.type.WolfArmorItem; +import org.geysermc.geyser.item.type.WritableBookItem; +import org.geysermc.geyser.item.type.WrittenBookItem; import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.registry.Registries; @@ -81,6 +111,7 @@ public final class Items { public static final Item ACACIA_PLANKS = register(new BlockItem(builder(), Blocks.ACACIA_PLANKS)); public static final Item CHERRY_PLANKS = register(new BlockItem(builder(), Blocks.CHERRY_PLANKS)); public static final Item DARK_OAK_PLANKS = register(new BlockItem(builder(), Blocks.DARK_OAK_PLANKS)); + public static final Item PALE_OAK_PLANKS = register(new BlockItem(builder(), Blocks.PALE_OAK_PLANKS)); public static final Item MANGROVE_PLANKS = register(new BlockItem(builder(), Blocks.MANGROVE_PLANKS)); public static final Item BAMBOO_PLANKS = register(new BlockItem(builder(), Blocks.BAMBOO_PLANKS)); public static final Item CRIMSON_PLANKS = register(new BlockItem(builder(), Blocks.CRIMSON_PLANKS)); @@ -93,6 +124,7 @@ public final class Items { public static final Item ACACIA_SAPLING = register(new BlockItem(builder(), Blocks.ACACIA_SAPLING)); public static final Item CHERRY_SAPLING = register(new BlockItem(builder(), Blocks.CHERRY_SAPLING)); public static final Item DARK_OAK_SAPLING = register(new BlockItem(builder(), Blocks.DARK_OAK_SAPLING)); + public static final Item PALE_OAK_SAPLING = register(new BlockItem(builder(), Blocks.PALE_OAK_SAPLING)); public static final Item MANGROVE_PROPAGULE = register(new BlockItem(builder(), Blocks.MANGROVE_PROPAGULE)); public static final Item BEDROCK = register(new BlockItem(builder(), Blocks.BEDROCK)); public static final Item SAND = register(new BlockItem(builder(), Blocks.SAND)); @@ -123,7 +155,7 @@ public final class Items { public static final Item RAW_IRON_BLOCK = register(new BlockItem(builder(), Blocks.RAW_IRON_BLOCK)); public static final Item RAW_COPPER_BLOCK = register(new BlockItem(builder(), Blocks.RAW_COPPER_BLOCK)); public static final Item RAW_GOLD_BLOCK = register(new BlockItem(builder(), Blocks.RAW_GOLD_BLOCK)); - public static final Item HEAVY_CORE = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.HEAVY_CORE)); + public static final Item HEAVY_CORE = register(new BlockItem(builder(), Blocks.HEAVY_CORE)); public static final Item AMETHYST_BLOCK = register(new BlockItem(builder(), Blocks.AMETHYST_BLOCK)); public static final Item BUDDING_AMETHYST = register(new BlockItem(builder(), Blocks.BUDDING_AMETHYST)); public static final Item IRON_BLOCK = register(new BlockItem(builder(), Blocks.IRON_BLOCK)); @@ -176,6 +208,7 @@ public final class Items { public static final Item JUNGLE_LOG = register(new BlockItem(builder(), Blocks.JUNGLE_LOG)); public static final Item ACACIA_LOG = register(new BlockItem(builder(), Blocks.ACACIA_LOG)); public static final Item CHERRY_LOG = register(new BlockItem(builder(), Blocks.CHERRY_LOG)); + public static final Item PALE_OAK_LOG = register(new BlockItem(builder(), Blocks.PALE_OAK_LOG)); public static final Item DARK_OAK_LOG = register(new BlockItem(builder(), Blocks.DARK_OAK_LOG)); public static final Item MANGROVE_LOG = register(new BlockItem(builder(), Blocks.MANGROVE_LOG)); public static final Item MANGROVE_ROOTS = register(new BlockItem(builder(), Blocks.MANGROVE_ROOTS)); @@ -190,6 +223,7 @@ public final class Items { public static final Item STRIPPED_ACACIA_LOG = register(new BlockItem(builder(), Blocks.STRIPPED_ACACIA_LOG)); public static final Item STRIPPED_CHERRY_LOG = register(new BlockItem(builder(), Blocks.STRIPPED_CHERRY_LOG)); public static final Item STRIPPED_DARK_OAK_LOG = register(new BlockItem(builder(), Blocks.STRIPPED_DARK_OAK_LOG)); + public static final Item STRIPPED_PALE_OAK_LOG = register(new BlockItem(builder(), Blocks.STRIPPED_PALE_OAK_LOG)); public static final Item STRIPPED_MANGROVE_LOG = register(new BlockItem(builder(), Blocks.STRIPPED_MANGROVE_LOG)); public static final Item STRIPPED_CRIMSON_STEM = register(new BlockItem(builder(), Blocks.STRIPPED_CRIMSON_STEM)); public static final Item STRIPPED_WARPED_STEM = register(new BlockItem(builder(), Blocks.STRIPPED_WARPED_STEM)); @@ -200,6 +234,7 @@ public final class Items { public static final Item STRIPPED_ACACIA_WOOD = register(new BlockItem(builder(), Blocks.STRIPPED_ACACIA_WOOD)); public static final Item STRIPPED_CHERRY_WOOD = register(new BlockItem(builder(), Blocks.STRIPPED_CHERRY_WOOD)); public static final Item STRIPPED_DARK_OAK_WOOD = register(new BlockItem(builder(), Blocks.STRIPPED_DARK_OAK_WOOD)); + public static final Item STRIPPED_PALE_OAK_WOOD = register(new BlockItem(builder(), Blocks.STRIPPED_PALE_OAK_WOOD)); public static final Item STRIPPED_MANGROVE_WOOD = register(new BlockItem(builder(), Blocks.STRIPPED_MANGROVE_WOOD)); public static final Item STRIPPED_CRIMSON_HYPHAE = register(new BlockItem(builder(), Blocks.STRIPPED_CRIMSON_HYPHAE)); public static final Item STRIPPED_WARPED_HYPHAE = register(new BlockItem(builder(), Blocks.STRIPPED_WARPED_HYPHAE)); @@ -210,6 +245,7 @@ public final class Items { public static final Item JUNGLE_WOOD = register(new BlockItem(builder(), Blocks.JUNGLE_WOOD)); public static final Item ACACIA_WOOD = register(new BlockItem(builder(), Blocks.ACACIA_WOOD)); public static final Item CHERRY_WOOD = register(new BlockItem(builder(), Blocks.CHERRY_WOOD)); + public static final Item PALE_OAK_WOOD = register(new BlockItem(builder(), Blocks.PALE_OAK_WOOD)); public static final Item DARK_OAK_WOOD = register(new BlockItem(builder(), Blocks.DARK_OAK_WOOD)); public static final Item MANGROVE_WOOD = register(new BlockItem(builder(), Blocks.MANGROVE_WOOD)); public static final Item CRIMSON_HYPHAE = register(new BlockItem(builder(), Blocks.CRIMSON_HYPHAE)); @@ -221,6 +257,7 @@ public final class Items { public static final Item ACACIA_LEAVES = register(new BlockItem(builder(), Blocks.ACACIA_LEAVES)); public static final Item CHERRY_LEAVES = register(new BlockItem(builder(), Blocks.CHERRY_LEAVES)); public static final Item DARK_OAK_LEAVES = register(new BlockItem(builder(), Blocks.DARK_OAK_LEAVES)); + public static final Item PALE_OAK_LEAVES = register(new BlockItem(builder(), Blocks.PALE_OAK_LEAVES)); public static final Item MANGROVE_LEAVES = register(new BlockItem(builder(), Blocks.MANGROVE_LEAVES)); public static final Item AZALEA_LEAVES = register(new BlockItem(builder(), Blocks.AZALEA_LEAVES)); public static final Item FLOWERING_AZALEA_LEAVES = register(new BlockItem(builder(), Blocks.FLOWERING_AZALEA_LEAVES)); @@ -283,9 +320,12 @@ public final class Items { public static final Item TWISTING_VINES = register(new BlockItem(builder(), Blocks.TWISTING_VINES)); public static final Item SUGAR_CANE = register(new BlockItem(builder(), Blocks.SUGAR_CANE)); public static final Item KELP = register(new BlockItem(builder(), Blocks.KELP)); - public static final Item MOSS_CARPET = register(new BlockItem(builder(), Blocks.MOSS_CARPET)); public static final Item PINK_PETALS = register(new BlockItem(builder(), Blocks.PINK_PETALS)); + public static final Item MOSS_CARPET = register(new BlockItem(builder(), Blocks.MOSS_CARPET)); public static final Item MOSS_BLOCK = register(new BlockItem(builder(), Blocks.MOSS_BLOCK)); + public static final Item PALE_MOSS_CARPET = register(new BlockItem(builder(), Blocks.PALE_MOSS_CARPET)); + public static final Item PALE_HANGING_MOSS = register(new BlockItem(builder(), Blocks.PALE_HANGING_MOSS)); + public static final Item PALE_MOSS_BLOCK = register(new BlockItem(builder(), Blocks.PALE_MOSS_BLOCK)); public static final Item HANGING_ROOTS = register(new BlockItem(builder(), Blocks.HANGING_ROOTS)); public static final Item BIG_DRIPLEAF = register(new BlockItem(builder(), Blocks.BIG_DRIPLEAF, Blocks.BIG_DRIPLEAF_STEM)); public static final Item SMALL_DRIPLEAF = register(new BlockItem(builder(), Blocks.SMALL_DRIPLEAF)); @@ -297,6 +337,7 @@ public final class Items { public static final Item ACACIA_SLAB = register(new BlockItem(builder(), Blocks.ACACIA_SLAB)); public static final Item CHERRY_SLAB = register(new BlockItem(builder(), Blocks.CHERRY_SLAB)); public static final Item DARK_OAK_SLAB = register(new BlockItem(builder(), Blocks.DARK_OAK_SLAB)); + public static final Item PALE_OAK_SLAB = register(new BlockItem(builder(), Blocks.PALE_OAK_SLAB)); public static final Item MANGROVE_SLAB = register(new BlockItem(builder(), Blocks.MANGROVE_SLAB)); public static final Item BAMBOO_SLAB = register(new BlockItem(builder(), Blocks.BAMBOO_SLAB)); public static final Item BAMBOO_MOSAIC_SLAB = register(new BlockItem(builder(), Blocks.BAMBOO_MOSAIC_SLAB)); @@ -337,6 +378,7 @@ public final class Items { public static final Item PURPUR_PILLAR = register(new BlockItem(builder(), Blocks.PURPUR_PILLAR)); public static final Item PURPUR_STAIRS = register(new BlockItem(builder(), Blocks.PURPUR_STAIRS)); public static final Item SPAWNER = register(new BlockItem(builder(), Blocks.SPAWNER)); + public static final Item CREAKING_HEART = register(new BlockItem(builder(), Blocks.CREAKING_HEART)); public static final Item CHEST = register(new BlockItem(builder(), Blocks.CHEST)); public static final Item CRAFTING_TABLE = register(new BlockItem(builder(), Blocks.CRAFTING_TABLE)); public static final Item FARMLAND = register(new BlockItem(builder(), Blocks.FARMLAND)); @@ -356,6 +398,7 @@ public final class Items { public static final Item ACACIA_FENCE = register(new BlockItem(builder(), Blocks.ACACIA_FENCE)); public static final Item CHERRY_FENCE = register(new BlockItem(builder(), Blocks.CHERRY_FENCE)); public static final Item DARK_OAK_FENCE = register(new BlockItem(builder(), Blocks.DARK_OAK_FENCE)); + public static final Item PALE_OAK_FENCE = register(new BlockItem(builder(), Blocks.PALE_OAK_FENCE)); public static final Item MANGROVE_FENCE = register(new BlockItem(builder(), Blocks.MANGROVE_FENCE)); public static final Item BAMBOO_FENCE = register(new BlockItem(builder(), Blocks.BAMBOO_FENCE)); public static final Item CRIMSON_FENCE = register(new BlockItem(builder(), Blocks.CRIMSON_FENCE)); @@ -417,7 +460,7 @@ public final class Items { public static final Item END_PORTAL_FRAME = register(new BlockItem(builder(), Blocks.END_PORTAL_FRAME)); public static final Item END_STONE = register(new BlockItem(builder(), Blocks.END_STONE)); public static final Item END_STONE_BRICKS = register(new BlockItem(builder(), Blocks.END_STONE_BRICKS)); - public static final Item DRAGON_EGG = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.DRAGON_EGG)); + public static final Item DRAGON_EGG = register(new BlockItem(builder(), Blocks.DRAGON_EGG)); public static final Item SANDSTONE_STAIRS = register(new BlockItem(builder(), Blocks.SANDSTONE_STAIRS)); public static final Item ENDER_CHEST = register(new BlockItem(builder(), Blocks.ENDER_CHEST)); public static final Item EMERALD_BLOCK = register(new BlockItem(builder(), Blocks.EMERALD_BLOCK)); @@ -428,13 +471,14 @@ public final class Items { public static final Item ACACIA_STAIRS = register(new BlockItem(builder(), Blocks.ACACIA_STAIRS)); public static final Item CHERRY_STAIRS = register(new BlockItem(builder(), Blocks.CHERRY_STAIRS)); public static final Item DARK_OAK_STAIRS = register(new BlockItem(builder(), Blocks.DARK_OAK_STAIRS)); + public static final Item PALE_OAK_STAIRS = register(new BlockItem(builder(), Blocks.PALE_OAK_STAIRS)); public static final Item MANGROVE_STAIRS = register(new BlockItem(builder(), Blocks.MANGROVE_STAIRS)); public static final Item BAMBOO_STAIRS = register(new BlockItem(builder(), Blocks.BAMBOO_STAIRS)); public static final Item BAMBOO_MOSAIC_STAIRS = register(new BlockItem(builder(), Blocks.BAMBOO_MOSAIC_STAIRS)); public static final Item CRIMSON_STAIRS = register(new BlockItem(builder(), Blocks.CRIMSON_STAIRS)); public static final Item WARPED_STAIRS = register(new BlockItem(builder(), Blocks.WARPED_STAIRS)); - public static final Item COMMAND_BLOCK = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.COMMAND_BLOCK)); - public static final Item BEACON = register(new BlockItem(builder().rarity(Rarity.RARE), Blocks.BEACON)); + public static final Item COMMAND_BLOCK = register(new BlockItem(builder(), Blocks.COMMAND_BLOCK)); + public static final Item BEACON = register(new BlockItem(builder(), Blocks.BEACON)); public static final Item COBBLESTONE_WALL = register(new BlockItem(builder(), Blocks.COBBLESTONE_WALL)); public static final Item MOSSY_COBBLESTONE_WALL = register(new BlockItem(builder(), Blocks.MOSSY_COBBLESTONE_WALL)); public static final Item BRICK_WALL = register(new BlockItem(builder(), Blocks.BRICK_WALL)); @@ -481,8 +525,8 @@ public final class Items { public static final Item GREEN_TERRACOTTA = register(new BlockItem(builder(), Blocks.GREEN_TERRACOTTA)); public static final Item RED_TERRACOTTA = register(new BlockItem(builder(), Blocks.RED_TERRACOTTA)); public static final Item BLACK_TERRACOTTA = register(new BlockItem(builder(), Blocks.BLACK_TERRACOTTA)); - public static final Item BARRIER = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.BARRIER)); - public static final Item LIGHT = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.LIGHT)); + public static final Item BARRIER = register(new BlockItem(builder(), Blocks.BARRIER)); + public static final Item LIGHT = register(new BlockItem(builder(), Blocks.LIGHT)); public static final Item HAY_BLOCK = register(new BlockItem(builder(), Blocks.HAY_BLOCK)); public static final Item WHITE_CARPET = register(new BlockItem(builder(), Blocks.WHITE_CARPET)); public static final Item ORANGE_CARPET = register(new BlockItem(builder(), Blocks.ORANGE_CARPET)); @@ -552,14 +596,14 @@ public final class Items { public static final Item CHISELED_RED_SANDSTONE = register(new BlockItem(builder(), Blocks.CHISELED_RED_SANDSTONE)); public static final Item CUT_RED_SANDSTONE = register(new BlockItem(builder(), Blocks.CUT_RED_SANDSTONE)); public static final Item RED_SANDSTONE_STAIRS = register(new BlockItem(builder(), Blocks.RED_SANDSTONE_STAIRS)); - public static final Item REPEATING_COMMAND_BLOCK = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.REPEATING_COMMAND_BLOCK)); - public static final Item CHAIN_COMMAND_BLOCK = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.CHAIN_COMMAND_BLOCK)); + public static final Item REPEATING_COMMAND_BLOCK = register(new BlockItem(builder(), Blocks.REPEATING_COMMAND_BLOCK)); + public static final Item CHAIN_COMMAND_BLOCK = register(new BlockItem(builder(), Blocks.CHAIN_COMMAND_BLOCK)); public static final Item MAGMA_BLOCK = register(new BlockItem(builder(), Blocks.MAGMA_BLOCK)); public static final Item NETHER_WART_BLOCK = register(new BlockItem(builder(), Blocks.NETHER_WART_BLOCK)); public static final Item WARPED_WART_BLOCK = register(new BlockItem(builder(), Blocks.WARPED_WART_BLOCK)); public static final Item RED_NETHER_BRICKS = register(new BlockItem(builder(), Blocks.RED_NETHER_BRICKS)); public static final Item BONE_BLOCK = register(new BlockItem(builder(), Blocks.BONE_BLOCK)); - public static final Item STRUCTURE_VOID = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.STRUCTURE_VOID)); + public static final Item STRUCTURE_VOID = register(new BlockItem(builder(), Blocks.STRUCTURE_VOID)); public static final Item SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.SHULKER_BOX)); public static final Item WHITE_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.WHITE_SHULKER_BOX)); public static final Item ORANGE_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.ORANGE_SHULKER_BOX)); @@ -658,7 +702,7 @@ public final class Items { public static final Item DEAD_FIRE_CORAL_FAN = register(new BlockItem(builder(), Blocks.DEAD_FIRE_CORAL_FAN, Blocks.DEAD_FIRE_CORAL_WALL_FAN)); public static final Item DEAD_HORN_CORAL_FAN = register(new BlockItem(builder(), Blocks.DEAD_HORN_CORAL_FAN, Blocks.DEAD_HORN_CORAL_WALL_FAN)); public static final Item BLUE_ICE = register(new BlockItem(builder(), Blocks.BLUE_ICE)); - public static final Item CONDUIT = register(new BlockItem(builder().rarity(Rarity.RARE), Blocks.CONDUIT)); + public static final Item CONDUIT = register(new BlockItem(builder(), Blocks.CONDUIT)); public static final Item POLISHED_GRANITE_STAIRS = register(new BlockItem(builder(), Blocks.POLISHED_GRANITE_STAIRS)); public static final Item SMOOTH_RED_SANDSTONE_STAIRS = register(new BlockItem(builder(), Blocks.SMOOTH_RED_SANDSTONE_STAIRS)); public static final Item MOSSY_STONE_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.MOSSY_STONE_BRICK_STAIRS)); @@ -729,6 +773,7 @@ public final class Items { public static final Item ACACIA_BUTTON = register(new BlockItem(builder(), Blocks.ACACIA_BUTTON)); public static final Item CHERRY_BUTTON = register(new BlockItem(builder(), Blocks.CHERRY_BUTTON)); public static final Item DARK_OAK_BUTTON = register(new BlockItem(builder(), Blocks.DARK_OAK_BUTTON)); + public static final Item PALE_OAK_BUTTON = register(new BlockItem(builder(), Blocks.PALE_OAK_BUTTON)); public static final Item MANGROVE_BUTTON = register(new BlockItem(builder(), Blocks.MANGROVE_BUTTON)); public static final Item BAMBOO_BUTTON = register(new BlockItem(builder(), Blocks.BAMBOO_BUTTON)); public static final Item CRIMSON_BUTTON = register(new BlockItem(builder(), Blocks.CRIMSON_BUTTON)); @@ -744,6 +789,7 @@ public final class Items { public static final Item ACACIA_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.ACACIA_PRESSURE_PLATE)); public static final Item CHERRY_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.CHERRY_PRESSURE_PLATE)); public static final Item DARK_OAK_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.DARK_OAK_PRESSURE_PLATE)); + public static final Item PALE_OAK_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.PALE_OAK_PRESSURE_PLATE)); public static final Item MANGROVE_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.MANGROVE_PRESSURE_PLATE)); public static final Item BAMBOO_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.BAMBOO_PRESSURE_PLATE)); public static final Item CRIMSON_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.CRIMSON_PRESSURE_PLATE)); @@ -756,6 +802,7 @@ public final class Items { public static final Item ACACIA_DOOR = register(new BlockItem(builder(), Blocks.ACACIA_DOOR)); public static final Item CHERRY_DOOR = register(new BlockItem(builder(), Blocks.CHERRY_DOOR)); public static final Item DARK_OAK_DOOR = register(new BlockItem(builder(), Blocks.DARK_OAK_DOOR)); + public static final Item PALE_OAK_DOOR = register(new BlockItem(builder(), Blocks.PALE_OAK_DOOR)); public static final Item MANGROVE_DOOR = register(new BlockItem(builder(), Blocks.MANGROVE_DOOR)); public static final Item BAMBOO_DOOR = register(new BlockItem(builder(), Blocks.BAMBOO_DOOR)); public static final Item CRIMSON_DOOR = register(new BlockItem(builder(), Blocks.CRIMSON_DOOR)); @@ -776,6 +823,7 @@ public final class Items { public static final Item ACACIA_TRAPDOOR = register(new BlockItem(builder(), Blocks.ACACIA_TRAPDOOR)); public static final Item CHERRY_TRAPDOOR = register(new BlockItem(builder(), Blocks.CHERRY_TRAPDOOR)); public static final Item DARK_OAK_TRAPDOOR = register(new BlockItem(builder(), Blocks.DARK_OAK_TRAPDOOR)); + public static final Item PALE_OAK_TRAPDOOR = register(new BlockItem(builder(), Blocks.PALE_OAK_TRAPDOOR)); public static final Item MANGROVE_TRAPDOOR = register(new BlockItem(builder(), Blocks.MANGROVE_TRAPDOOR)); public static final Item BAMBOO_TRAPDOOR = register(new BlockItem(builder(), Blocks.BAMBOO_TRAPDOOR)); public static final Item CRIMSON_TRAPDOOR = register(new BlockItem(builder(), Blocks.CRIMSON_TRAPDOOR)); @@ -795,6 +843,7 @@ public final class Items { public static final Item ACACIA_FENCE_GATE = register(new BlockItem(builder(), Blocks.ACACIA_FENCE_GATE)); public static final Item CHERRY_FENCE_GATE = register(new BlockItem(builder(), Blocks.CHERRY_FENCE_GATE)); public static final Item DARK_OAK_FENCE_GATE = register(new BlockItem(builder(), Blocks.DARK_OAK_FENCE_GATE)); + public static final Item PALE_OAK_FENCE_GATE = register(new BlockItem(builder(), Blocks.PALE_OAK_FENCE_GATE)); public static final Item MANGROVE_FENCE_GATE = register(new BlockItem(builder(), Blocks.MANGROVE_FENCE_GATE)); public static final Item BAMBOO_FENCE_GATE = register(new BlockItem(builder(), Blocks.BAMBOO_FENCE_GATE)); public static final Item CRIMSON_FENCE_GATE = register(new BlockItem(builder(), Blocks.CRIMSON_FENCE_GATE)); @@ -811,7 +860,8 @@ public final class Items { public static final Item HOPPER_MINECART = register(new Item("hopper_minecart", builder().stackSize(1))); public static final Item CARROT_ON_A_STICK = register(new Item("carrot_on_a_stick", builder().stackSize(1).maxDamage(25))); public static final Item WARPED_FUNGUS_ON_A_STICK = register(new Item("warped_fungus_on_a_stick", builder().stackSize(1).maxDamage(100))); - public static final Item ELYTRA = register(new ElytraItem("elytra", builder().stackSize(1).maxDamage(432).rarity(Rarity.UNCOMMON))); + public static final Item PHANTOM_MEMBRANE = register(new Item("phantom_membrane", builder())); + public static final Item ELYTRA = register(new ElytraItem("elytra", builder().stackSize(1).maxDamage(432))); public static final Item OAK_BOAT = register(new BoatItem("oak_boat", builder().stackSize(1))); public static final Item OAK_CHEST_BOAT = register(new BoatItem("oak_chest_boat", builder().stackSize(1))); public static final Item SPRUCE_BOAT = register(new BoatItem("spruce_boat", builder().stackSize(1))); @@ -826,12 +876,14 @@ public final class Items { public static final Item CHERRY_CHEST_BOAT = register(new BoatItem("cherry_chest_boat", builder().stackSize(1))); public static final Item DARK_OAK_BOAT = register(new BoatItem("dark_oak_boat", builder().stackSize(1))); public static final Item DARK_OAK_CHEST_BOAT = register(new BoatItem("dark_oak_chest_boat", builder().stackSize(1))); + public static final Item PALE_OAK_BOAT = register(new BoatItem("pale_oak_boat", builder().stackSize(1))); + public static final Item PALE_OAK_CHEST_BOAT = register(new BoatItem("pale_oak_chest_boat", builder().stackSize(1))); public static final Item MANGROVE_BOAT = register(new BoatItem("mangrove_boat", builder().stackSize(1))); public static final Item MANGROVE_CHEST_BOAT = register(new BoatItem("mangrove_chest_boat", builder().stackSize(1))); public static final Item BAMBOO_RAFT = register(new BoatItem("bamboo_raft", builder().stackSize(1))); public static final Item BAMBOO_CHEST_RAFT = register(new BoatItem("bamboo_chest_raft", builder().stackSize(1))); - public static final Item STRUCTURE_BLOCK = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.STRUCTURE_BLOCK)); - public static final Item JIGSAW = register(new BlockItem(builder().rarity(Rarity.EPIC), Blocks.JIGSAW)); + public static final Item STRUCTURE_BLOCK = register(new BlockItem(builder(), Blocks.STRUCTURE_BLOCK)); + public static final Item JIGSAW = register(new BlockItem(builder(), Blocks.JIGSAW)); public static final Item TURTLE_HELMET = register(new ArmorItem("turtle_helmet", ArmorMaterial.TURTLE, builder().stackSize(1).maxDamage(275))); public static final Item TURTLE_SCUTE = register(new Item("turtle_scute", builder())); public static final Item ARMADILLO_SCUTE = register(new Item("armadillo_scute", builder())); @@ -922,8 +974,8 @@ public final class Items { public static final Item PORKCHOP = register(new Item("porkchop", builder())); public static final Item COOKED_PORKCHOP = register(new Item("cooked_porkchop", builder())); public static final Item PAINTING = register(new Item("painting", builder())); - public static final Item GOLDEN_APPLE = register(new Item("golden_apple", builder().rarity(Rarity.RARE))); - public static final Item ENCHANTED_GOLDEN_APPLE = register(new Item("enchanted_golden_apple", builder().rarity(Rarity.EPIC))); + public static final Item GOLDEN_APPLE = register(new Item("golden_apple", builder())); + public static final Item ENCHANTED_GOLDEN_APPLE = register(new Item("enchanted_golden_apple", builder())); public static final Item OAK_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.OAK_SIGN, Blocks.OAK_WALL_SIGN)); public static final Item SPRUCE_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.SPRUCE_SIGN, Blocks.SPRUCE_WALL_SIGN)); public static final Item BIRCH_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.BIRCH_SIGN, Blocks.BIRCH_WALL_SIGN)); @@ -931,6 +983,7 @@ public final class Items { public static final Item ACACIA_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.ACACIA_SIGN, Blocks.ACACIA_WALL_SIGN)); public static final Item CHERRY_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.CHERRY_SIGN, Blocks.CHERRY_WALL_SIGN)); public static final Item DARK_OAK_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.DARK_OAK_SIGN, Blocks.DARK_OAK_WALL_SIGN)); + public static final Item PALE_OAK_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.PALE_OAK_SIGN, Blocks.PALE_OAK_WALL_SIGN)); public static final Item MANGROVE_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.MANGROVE_SIGN, Blocks.MANGROVE_WALL_SIGN)); public static final Item BAMBOO_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.BAMBOO_SIGN, Blocks.BAMBOO_WALL_SIGN)); public static final Item CRIMSON_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.CRIMSON_SIGN, Blocks.CRIMSON_WALL_SIGN)); @@ -942,6 +995,7 @@ public final class Items { public static final Item ACACIA_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.ACACIA_HANGING_SIGN, Blocks.ACACIA_WALL_HANGING_SIGN)); public static final Item CHERRY_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.CHERRY_HANGING_SIGN, Blocks.CHERRY_WALL_HANGING_SIGN)); public static final Item DARK_OAK_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.DARK_OAK_HANGING_SIGN, Blocks.DARK_OAK_WALL_HANGING_SIGN)); + public static final Item PALE_OAK_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.PALE_OAK_HANGING_SIGN, Blocks.PALE_OAK_WALL_HANGING_SIGN)); public static final Item MANGROVE_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.MANGROVE_HANGING_SIGN, Blocks.MANGROVE_WALL_HANGING_SIGN)); public static final Item BAMBOO_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.BAMBOO_HANGING_SIGN, Blocks.BAMBOO_WALL_HANGING_SIGN)); public static final Item CRIMSON_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.CRIMSON_HANGING_SIGN, Blocks.CRIMSON_WALL_HANGING_SIGN)); @@ -969,6 +1023,22 @@ public final class Items { public static final Item COMPASS = register(new CompassItem("compass", builder())); public static final Item RECOVERY_COMPASS = register(new Item("recovery_compass", builder())); public static final Item BUNDLE = register(new Item("bundle", builder().stackSize(1))); + public static final Item WHITE_BUNDLE = register(new Item("white_bundle", builder().stackSize(1))); + public static final Item ORANGE_BUNDLE = register(new Item("orange_bundle", builder().stackSize(1))); + public static final Item MAGENTA_BUNDLE = register(new Item("magenta_bundle", builder().stackSize(1))); + public static final Item LIGHT_BLUE_BUNDLE = register(new Item("light_blue_bundle", builder().stackSize(1))); + public static final Item YELLOW_BUNDLE = register(new Item("yellow_bundle", builder().stackSize(1))); + public static final Item LIME_BUNDLE = register(new Item("lime_bundle", builder().stackSize(1))); + public static final Item PINK_BUNDLE = register(new Item("pink_bundle", builder().stackSize(1))); + public static final Item GRAY_BUNDLE = register(new Item("gray_bundle", builder().stackSize(1))); + public static final Item LIGHT_GRAY_BUNDLE = register(new Item("light_gray_bundle", builder().stackSize(1))); + public static final Item CYAN_BUNDLE = register(new Item("cyan_bundle", builder().stackSize(1))); + public static final Item PURPLE_BUNDLE = register(new Item("purple_bundle", builder().stackSize(1))); + public static final Item BLUE_BUNDLE = register(new Item("blue_bundle", builder().stackSize(1))); + public static final Item BROWN_BUNDLE = register(new Item("brown_bundle", builder().stackSize(1))); + public static final Item GREEN_BUNDLE = register(new Item("green_bundle", builder().stackSize(1))); + public static final Item RED_BUNDLE = register(new Item("red_bundle", builder().stackSize(1))); + public static final Item BLACK_BUNDLE = register(new Item("black_bundle", builder().stackSize(1))); public static final Item FISHING_ROD = register(new FishingRodItem("fishing_rod", builder().stackSize(1).maxDamage(64))); public static final Item CLOCK = register(new Item("clock", builder())); public static final Item SPYGLASS = register(new Item("spyglass", builder().stackSize(1))); @@ -1036,14 +1106,14 @@ public final class Items { public static final Item GHAST_TEAR = register(new Item("ghast_tear", builder())); public static final Item GOLD_NUGGET = register(new Item("gold_nugget", builder())); public static final Item NETHER_WART = register(new BlockItem(builder(), Blocks.NETHER_WART)); - public static final Item POTION = register(new PotionItem("potion", builder().stackSize(1))); public static final Item GLASS_BOTTLE = register(new Item("glass_bottle", builder())); + public static final Item POTION = register(new PotionItem("potion", builder().stackSize(1))); public static final Item SPIDER_EYE = register(new Item("spider_eye", builder())); public static final Item FERMENTED_SPIDER_EYE = register(new Item("fermented_spider_eye", builder())); public static final Item BLAZE_POWDER = register(new Item("blaze_powder", builder())); public static final Item MAGMA_CREAM = register(new Item("magma_cream", builder())); public static final Item BREWING_STAND = register(new BlockItem(builder(), Blocks.BREWING_STAND)); - public static final Item CAULDRON = register(new BlockItem(builder(), Blocks.CAULDRON, Blocks.WATER_CAULDRON, Blocks.POWDER_SNOW_CAULDRON, Blocks.LAVA_CAULDRON)); + public static final Item CAULDRON = register(new BlockItem(builder(), Blocks.CAULDRON, Blocks.LAVA_CAULDRON, Blocks.WATER_CAULDRON, Blocks.POWDER_SNOW_CAULDRON)); public static final Item ENDER_EYE = register(new Item("ender_eye", builder())); public static final Item GLISTERING_MELON_SLICE = register(new Item("glistering_melon_slice", builder())); public static final Item ARMADILLO_SPAWN_EGG = register(new SpawnEggItem("armadillo_spawn_egg", builder())); @@ -1122,16 +1192,18 @@ public final class Items { public static final Item WITHER_SKELETON_SPAWN_EGG = register(new SpawnEggItem("wither_skeleton_spawn_egg", builder())); public static final Item WOLF_SPAWN_EGG = register(new SpawnEggItem("wolf_spawn_egg", builder())); public static final Item ZOGLIN_SPAWN_EGG = register(new SpawnEggItem("zoglin_spawn_egg", builder())); + public static final Item CREAKING_SPAWN_EGG = register(new SpawnEggItem("creaking_spawn_egg", builder())); public static final Item ZOMBIE_SPAWN_EGG = register(new SpawnEggItem("zombie_spawn_egg", builder())); public static final Item ZOMBIE_HORSE_SPAWN_EGG = register(new SpawnEggItem("zombie_horse_spawn_egg", builder())); public static final Item ZOMBIE_VILLAGER_SPAWN_EGG = register(new SpawnEggItem("zombie_villager_spawn_egg", builder())); public static final Item ZOMBIFIED_PIGLIN_SPAWN_EGG = register(new SpawnEggItem("zombified_piglin_spawn_egg", builder())); - public static final Item EXPERIENCE_BOTTLE = register(new Item("experience_bottle", builder().rarity(Rarity.UNCOMMON))); + public static final Item EXPERIENCE_BOTTLE = register(new Item("experience_bottle", builder())); public static final Item FIRE_CHARGE = register(new Item("fire_charge", builder())); public static final Item WIND_CHARGE = register(new Item("wind_charge", builder())); public static final Item WRITABLE_BOOK = register(new WritableBookItem("writable_book", builder().stackSize(1))); public static final Item WRITTEN_BOOK = register(new WrittenBookItem("written_book", builder().stackSize(16))); - public static final Item MACE = register(new MaceItem("mace", builder().stackSize(1).maxDamage(500).rarity(Rarity.EPIC))); + public static final Item BREEZE_ROD = register(new Item("breeze_rod", builder())); + public static final Item MACE = register(new MaceItem("mace", builder().stackSize(1).maxDamage(500))); public static final Item ITEM_FRAME = register(new Item("item_frame", builder())); public static final Item GLOW_ITEM_FRAME = register(new Item("glow_item_frame", builder())); public static final Item FLOWER_POT = register(new BlockItem(builder(), Blocks.FLOWER_POT)); @@ -1141,18 +1213,18 @@ public final class Items { public static final Item POISONOUS_POTATO = register(new Item("poisonous_potato", builder())); public static final Item MAP = register(new MapItem("map", builder())); public static final Item GOLDEN_CARROT = register(new Item("golden_carrot", builder())); - public static final Item SKELETON_SKULL = register(new BlockItem(builder().rarity(Rarity.UNCOMMON), Blocks.SKELETON_SKULL, Blocks.SKELETON_WALL_SKULL)); - public static final Item WITHER_SKELETON_SKULL = register(new BlockItem(builder().rarity(Rarity.UNCOMMON), Blocks.WITHER_SKELETON_SKULL, Blocks.WITHER_SKELETON_WALL_SKULL)); - public static final Item PLAYER_HEAD = register(new PlayerHeadItem(builder().rarity(Rarity.UNCOMMON), Blocks.PLAYER_HEAD, Blocks.PLAYER_WALL_HEAD)); - public static final Item ZOMBIE_HEAD = register(new BlockItem(builder().rarity(Rarity.UNCOMMON), Blocks.ZOMBIE_HEAD, Blocks.ZOMBIE_WALL_HEAD)); - public static final Item CREEPER_HEAD = register(new BlockItem(builder().rarity(Rarity.UNCOMMON), Blocks.CREEPER_HEAD, Blocks.CREEPER_WALL_HEAD)); - public static final Item DRAGON_HEAD = register(new BlockItem(builder().rarity(Rarity.UNCOMMON), Blocks.DRAGON_HEAD, Blocks.DRAGON_WALL_HEAD)); - public static final Item PIGLIN_HEAD = register(new BlockItem(builder().rarity(Rarity.UNCOMMON), Blocks.PIGLIN_HEAD, Blocks.PIGLIN_WALL_HEAD)); - public static final Item NETHER_STAR = register(new Item("nether_star", builder().rarity(Rarity.UNCOMMON))); + public static final Item SKELETON_SKULL = register(new BlockItem(builder(), Blocks.SKELETON_SKULL, Blocks.SKELETON_WALL_SKULL)); + public static final Item WITHER_SKELETON_SKULL = register(new BlockItem(builder(), Blocks.WITHER_SKELETON_SKULL, Blocks.WITHER_SKELETON_WALL_SKULL)); + public static final Item PLAYER_HEAD = register(new PlayerHeadItem(builder(), Blocks.PLAYER_HEAD, Blocks.PLAYER_WALL_HEAD)); + public static final Item ZOMBIE_HEAD = register(new BlockItem(builder(), Blocks.ZOMBIE_HEAD, Blocks.ZOMBIE_WALL_HEAD)); + public static final Item CREEPER_HEAD = register(new BlockItem(builder(), Blocks.CREEPER_HEAD, Blocks.CREEPER_WALL_HEAD)); + public static final Item DRAGON_HEAD = register(new BlockItem(builder(), Blocks.DRAGON_HEAD, Blocks.DRAGON_WALL_HEAD)); + public static final Item PIGLIN_HEAD = register(new BlockItem(builder(), Blocks.PIGLIN_HEAD, Blocks.PIGLIN_WALL_HEAD)); + public static final Item NETHER_STAR = register(new Item("nether_star", builder())); public static final Item PUMPKIN_PIE = register(new Item("pumpkin_pie", builder())); public static final Item FIREWORK_ROCKET = register(new FireworkRocketItem("firework_rocket", builder())); public static final Item FIREWORK_STAR = register(new FireworkStarItem("firework_star", builder())); - public static final Item ENCHANTED_BOOK = register(new EnchantedBookItem("enchanted_book", builder().stackSize(1).rarity(Rarity.UNCOMMON))); + public static final Item ENCHANTED_BOOK = register(new EnchantedBookItem("enchanted_book", builder().stackSize(1))); public static final Item NETHER_BRICK = register(new Item("nether_brick", builder())); public static final Item PRISMARINE_SHARD = register(new Item("prismarine_shard", builder())); public static final Item PRISMARINE_CRYSTALS = register(new Item("prismarine_crystals", builder())); @@ -1162,13 +1234,13 @@ public final class Items { public static final Item RABBIT_FOOT = register(new Item("rabbit_foot", builder())); public static final Item RABBIT_HIDE = register(new Item("rabbit_hide", builder())); public static final Item ARMOR_STAND = register(new Item("armor_stand", builder().stackSize(16))); - public static final Item IRON_HORSE_ARMOR = register(new ArmorItem("iron_horse_armor", ArmorMaterial.IRON, builder().stackSize(1))); - public static final Item GOLDEN_HORSE_ARMOR = register(new ArmorItem("golden_horse_armor", ArmorMaterial.GOLD, builder().stackSize(1))); - public static final Item DIAMOND_HORSE_ARMOR = register(new ArmorItem("diamond_horse_armor", ArmorMaterial.DIAMOND, builder().stackSize(1))); + public static final Item IRON_HORSE_ARMOR = register(new Item("iron_horse_armor", builder().stackSize(1))); + public static final Item GOLDEN_HORSE_ARMOR = register(new Item("golden_horse_armor", builder().stackSize(1))); + public static final Item DIAMOND_HORSE_ARMOR = register(new Item("diamond_horse_armor", builder().stackSize(1))); public static final Item LEATHER_HORSE_ARMOR = register(new DyeableArmorItem("leather_horse_armor", ArmorMaterial.LEATHER, builder().stackSize(1))); public static final Item LEAD = register(new Item("lead", builder())); public static final Item NAME_TAG = register(new Item("name_tag", builder())); - public static final Item COMMAND_BLOCK_MINECART = register(new Item("command_block_minecart", builder().stackSize(1).rarity(Rarity.EPIC))); + public static final Item COMMAND_BLOCK_MINECART = register(new Item("command_block_minecart", builder().stackSize(1))); public static final Item MUTTON = register(new Item("mutton", builder())); public static final Item COOKED_MUTTON = register(new Item("cooked_mutton", builder())); public static final Item WHITE_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.WHITE_BANNER, Blocks.WHITE_WALL_BANNER)); @@ -1187,7 +1259,7 @@ public final class Items { public static final Item GREEN_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.GREEN_BANNER, Blocks.GREEN_WALL_BANNER)); public static final Item RED_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.RED_BANNER, Blocks.RED_WALL_BANNER)); public static final Item BLACK_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.BLACK_BANNER, Blocks.BLACK_WALL_BANNER)); - public static final Item END_CRYSTAL = register(new Item("end_crystal", builder().rarity(Rarity.RARE))); + public static final Item END_CRYSTAL = register(new Item("end_crystal", builder())); public static final Item CHORUS_FRUIT = register(new Item("chorus_fruit", builder())); public static final Item POPPED_CHORUS_FRUIT = register(new Item("popped_chorus_fruit", builder())); public static final Item TORCHFLOWER_SEEDS = register(new BlockItem("torchflower_seeds", builder(), Blocks.TORCHFLOWER_CROP)); @@ -1195,52 +1267,53 @@ public final class Items { public static final Item BEETROOT = register(new Item("beetroot", builder())); public static final Item BEETROOT_SEEDS = register(new BlockItem("beetroot_seeds", builder(), Blocks.BEETROOTS)); public static final Item BEETROOT_SOUP = register(new Item("beetroot_soup", builder().stackSize(1))); - public static final Item DRAGON_BREATH = register(new Item("dragon_breath", builder().rarity(Rarity.UNCOMMON))); + public static final Item DRAGON_BREATH = register(new Item("dragon_breath", builder())); public static final Item SPLASH_POTION = register(new PotionItem("splash_potion", builder().stackSize(1))); public static final Item SPECTRAL_ARROW = register(new Item("spectral_arrow", builder())); public static final Item TIPPED_ARROW = register(new TippedArrowItem("tipped_arrow", builder())); public static final Item LINGERING_POTION = register(new PotionItem("lingering_potion", builder().stackSize(1))); public static final Item SHIELD = register(new ShieldItem("shield", builder().stackSize(1).maxDamage(336))); - public static final Item TOTEM_OF_UNDYING = register(new Item("totem_of_undying", builder().stackSize(1).rarity(Rarity.UNCOMMON))); + public static final Item TOTEM_OF_UNDYING = register(new Item("totem_of_undying", builder().stackSize(1))); public static final Item SHULKER_SHELL = register(new Item("shulker_shell", builder())); public static final Item IRON_NUGGET = register(new Item("iron_nugget", builder())); - public static final Item KNOWLEDGE_BOOK = register(new Item("knowledge_book", builder().stackSize(1).rarity(Rarity.EPIC))); - public static final Item DEBUG_STICK = register(new Item("debug_stick", builder().stackSize(1).rarity(Rarity.EPIC).glint(true))); - public static final Item MUSIC_DISC_13 = register(new Item("music_disc_13", builder().stackSize(1).rarity(Rarity.RARE))); - public static final Item MUSIC_DISC_CAT = register(new Item("music_disc_cat", builder().stackSize(1).rarity(Rarity.RARE))); - public static final Item MUSIC_DISC_BLOCKS = register(new Item("music_disc_blocks", builder().stackSize(1).rarity(Rarity.RARE))); - public static final Item MUSIC_DISC_CHIRP = register(new Item("music_disc_chirp", builder().stackSize(1).rarity(Rarity.RARE))); - public static final Item MUSIC_DISC_CREATOR = register(new Item("music_disc_creator", builder().stackSize(1).rarity(Rarity.RARE))); - public static final Item MUSIC_DISC_CREATOR_MUSIC_BOX = register(new Item("music_disc_creator_music_box", builder().stackSize(1).rarity(Rarity.RARE))); - public static final Item MUSIC_DISC_FAR = register(new Item("music_disc_far", builder().stackSize(1).rarity(Rarity.RARE))); - public static final Item MUSIC_DISC_MALL = register(new Item("music_disc_mall", builder().stackSize(1).rarity(Rarity.RARE))); - public static final Item MUSIC_DISC_MELLOHI = register(new Item("music_disc_mellohi", builder().stackSize(1).rarity(Rarity.RARE))); - public static final Item MUSIC_DISC_STAL = register(new Item("music_disc_stal", builder().stackSize(1).rarity(Rarity.RARE))); - public static final Item MUSIC_DISC_STRAD = register(new Item("music_disc_strad", builder().stackSize(1).rarity(Rarity.RARE))); - public static final Item MUSIC_DISC_WARD = register(new Item("music_disc_ward", builder().stackSize(1).rarity(Rarity.RARE))); - public static final Item MUSIC_DISC_11 = register(new Item("music_disc_11", builder().stackSize(1).rarity(Rarity.RARE))); - public static final Item MUSIC_DISC_WAIT = register(new Item("music_disc_wait", builder().stackSize(1).rarity(Rarity.RARE))); - public static final Item MUSIC_DISC_OTHERSIDE = register(new Item("music_disc_otherside", builder().stackSize(1).rarity(Rarity.RARE))); - public static final Item MUSIC_DISC_RELIC = register(new Item("music_disc_relic", builder().stackSize(1).rarity(Rarity.RARE))); - public static final Item MUSIC_DISC_5 = register(new Item("music_disc_5", builder().stackSize(1).rarity(Rarity.RARE))); - public static final Item MUSIC_DISC_PIGSTEP = register(new Item("music_disc_pigstep", builder().stackSize(1).rarity(Rarity.RARE))); - public static final Item MUSIC_DISC_PRECIPICE = register(new Item("music_disc_precipice", builder().stackSize(1).rarity(Rarity.RARE))); + public static final Item KNOWLEDGE_BOOK = register(new Item("knowledge_book", builder().stackSize(1))); + public static final Item DEBUG_STICK = register(new Item("debug_stick", builder().stackSize(1))); + public static final Item MUSIC_DISC_13 = register(new Item("music_disc_13", builder().stackSize(1))); + public static final Item MUSIC_DISC_CAT = register(new Item("music_disc_cat", builder().stackSize(1))); + public static final Item MUSIC_DISC_BLOCKS = register(new Item("music_disc_blocks", builder().stackSize(1))); + public static final Item MUSIC_DISC_CHIRP = register(new Item("music_disc_chirp", builder().stackSize(1))); + public static final Item MUSIC_DISC_CREATOR = register(new Item("music_disc_creator", builder().stackSize(1))); + public static final Item MUSIC_DISC_CREATOR_MUSIC_BOX = register(new Item("music_disc_creator_music_box", builder().stackSize(1))); + public static final Item MUSIC_DISC_FAR = register(new Item("music_disc_far", builder().stackSize(1))); + public static final Item MUSIC_DISC_MALL = register(new Item("music_disc_mall", builder().stackSize(1))); + public static final Item MUSIC_DISC_MELLOHI = register(new Item("music_disc_mellohi", builder().stackSize(1))); + public static final Item MUSIC_DISC_STAL = register(new Item("music_disc_stal", builder().stackSize(1))); + public static final Item MUSIC_DISC_STRAD = register(new Item("music_disc_strad", builder().stackSize(1))); + public static final Item MUSIC_DISC_WARD = register(new Item("music_disc_ward", builder().stackSize(1))); + public static final Item MUSIC_DISC_11 = register(new Item("music_disc_11", builder().stackSize(1))); + public static final Item MUSIC_DISC_WAIT = register(new Item("music_disc_wait", builder().stackSize(1))); + public static final Item MUSIC_DISC_OTHERSIDE = register(new Item("music_disc_otherside", builder().stackSize(1))); + public static final Item MUSIC_DISC_RELIC = register(new Item("music_disc_relic", builder().stackSize(1))); + public static final Item MUSIC_DISC_5 = register(new Item("music_disc_5", builder().stackSize(1))); + public static final Item MUSIC_DISC_PIGSTEP = register(new Item("music_disc_pigstep", builder().stackSize(1))); + public static final Item MUSIC_DISC_PRECIPICE = register(new Item("music_disc_precipice", builder().stackSize(1))); public static final Item DISC_FRAGMENT_5 = register(new Item("disc_fragment_5", builder())); - public static final Item TRIDENT = register(new Item("trident", builder().stackSize(1).maxDamage(250).attackDamage(9.0).rarity(Rarity.EPIC))); - public static final Item PHANTOM_MEMBRANE = register(new Item("phantom_membrane", builder())); + public static final Item TRIDENT = register(new Item("trident", builder().stackSize(1).maxDamage(250).attackDamage(9.0))); public static final Item NAUTILUS_SHELL = register(new Item("nautilus_shell", builder())); - public static final Item HEART_OF_THE_SEA = register(new Item("heart_of_the_sea", builder().rarity(Rarity.UNCOMMON))); + public static final Item HEART_OF_THE_SEA = register(new Item("heart_of_the_sea", builder())); public static final Item CROSSBOW = register(new CrossbowItem("crossbow", builder().stackSize(1).maxDamage(465))); public static final Item SUSPICIOUS_STEW = register(new Item("suspicious_stew", builder().stackSize(1))); public static final Item LOOM = register(new BlockItem(builder(), Blocks.LOOM)); public static final Item FLOWER_BANNER_PATTERN = register(new Item("flower_banner_pattern", builder().stackSize(1))); - public static final Item CREEPER_BANNER_PATTERN = register(new Item("creeper_banner_pattern", builder().stackSize(1).rarity(Rarity.UNCOMMON))); - public static final Item SKULL_BANNER_PATTERN = register(new Item("skull_banner_pattern", builder().stackSize(1).rarity(Rarity.UNCOMMON))); - public static final Item MOJANG_BANNER_PATTERN = register(new Item("mojang_banner_pattern", builder().stackSize(1).rarity(Rarity.EPIC))); + public static final Item CREEPER_BANNER_PATTERN = register(new Item("creeper_banner_pattern", builder().stackSize(1))); + public static final Item SKULL_BANNER_PATTERN = register(new Item("skull_banner_pattern", builder().stackSize(1))); + public static final Item MOJANG_BANNER_PATTERN = register(new Item("mojang_banner_pattern", builder().stackSize(1))); public static final Item GLOBE_BANNER_PATTERN = register(new Item("globe_banner_pattern", builder().stackSize(1))); - public static final Item PIGLIN_BANNER_PATTERN = register(new Item("piglin_banner_pattern", builder().stackSize(1).rarity(Rarity.UNCOMMON))); - public static final Item FLOW_BANNER_PATTERN = register(new Item("flow_banner_pattern", builder().stackSize(1).rarity(Rarity.RARE))); - public static final Item GUSTER_BANNER_PATTERN = register(new Item("guster_banner_pattern", builder().stackSize(1).rarity(Rarity.RARE))); + public static final Item PIGLIN_BANNER_PATTERN = register(new Item("piglin_banner_pattern", builder().stackSize(1))); + public static final Item FLOW_BANNER_PATTERN = register(new Item("flow_banner_pattern", builder().stackSize(1))); + public static final Item GUSTER_BANNER_PATTERN = register(new Item("guster_banner_pattern", builder().stackSize(1))); + public static final Item FIELD_MASONED_BANNER_PATTERN = register(new Item("field_masoned_banner_pattern", builder().stackSize(1))); + public static final Item BORDURE_INDENTED_BANNER_PATTERN = register(new Item("bordure_indented_banner_pattern", builder().stackSize(1))); public static final Item GOAT_HORN = register(new GoatHornItem("goat_horn", builder().stackSize(1))); public static final Item COMPOSTER = register(new BlockItem(builder(), Blocks.COMPOSTER)); public static final Item BARREL = register(new BlockItem(builder(), Blocks.BARREL)); @@ -1369,8 +1442,7 @@ public final class Items { public static final Item TRIAL_KEY = register(new Item("trial_key", builder())); public static final Item OMINOUS_TRIAL_KEY = register(new Item("ominous_trial_key", builder())); public static final Item VAULT = register(new BlockItem(builder(), Blocks.VAULT)); - public static final Item OMINOUS_BOTTLE = register(new OminousBottleItem("ominous_bottle", builder())); - public static final Item BREEZE_ROD = register(new Item("breeze_rod", builder())); + public static final Item OMINOUS_BOTTLE = register(new Item("ominous_bottle", builder())); public static final int AIR_ID = AIR.javaId(); diff --git a/core/src/main/java/org/geysermc/geyser/item/enchantment/Enchantment.java b/core/src/main/java/org/geysermc/geyser/item/enchantment/Enchantment.java index 301f69a5f..e0b4f6e0f 100644 --- a/core/src/main/java/org/geysermc/geyser/item/enchantment/Enchantment.java +++ b/core/src/main/java/org/geysermc/geyser/item/enchantment/Enchantment.java @@ -25,52 +25,47 @@ package org.geysermc.geyser.item.enchantment; -import it.unimi.dsi.fastutil.ints.IntArrays; -import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.nbt.NbtMap; import org.geysermc.geyser.inventory.item.BedrockEnchantment; import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.registry.Registries; +import org.geysermc.geyser.session.cache.registry.JavaRegistries; import org.geysermc.geyser.session.cache.registry.RegistryEntryContext; +import org.geysermc.geyser.session.cache.tags.GeyserHolderSet; import org.geysermc.geyser.translator.text.MessageTranslator; -import org.geysermc.geyser.util.MinecraftKey; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet; import java.util.HashSet; -import java.util.List; import java.util.Map; import java.util.Set; -import java.util.function.ToIntFunction; /** - * @param description only populated if {@link #bedrockEnchantment()} is not null. + * @param description only populated if {@link #bedrockEnchantment()} is null. * @param anvilCost also as a rarity multiplier */ public record Enchantment(String identifier, Set effects, - HolderSet supportedItems, + GeyserHolderSet supportedItems, int maxLevel, String description, int anvilCost, - HolderSet exclusiveSet, + GeyserHolderSet exclusiveSet, @Nullable BedrockEnchantment bedrockEnchantment) { public static Enchantment read(RegistryEntryContext context) { NbtMap data = context.data(); Set effects = readEnchantmentComponents(data.getCompound("effects")); - HolderSet supportedItems = readHolderSet(data.get("supported_items"), itemId -> Registries.JAVA_ITEM_IDENTIFIERS.getOrDefault(itemId.asString(), Items.AIR).javaId()); + GeyserHolderSet supportedItems = GeyserHolderSet.readHolderSet(context.session(), JavaRegistries.ITEM, data.get("supported_items"), itemId -> Registries.JAVA_ITEM_IDENTIFIERS.getOrDefault(itemId.asString(), Items.AIR).javaId()); int maxLevel = data.getInt("max_level"); int anvilCost = data.getInt("anvil_cost"); - HolderSet exclusiveSet = readHolderSet(data.getOrDefault("exclusive_set", null), context::getNetworkId); + GeyserHolderSet exclusiveSet = GeyserHolderSet.readHolderSet(context.session(), JavaRegistries.ENCHANTMENT, data.get("exclusive_set"), context::getNetworkId); BedrockEnchantment bedrockEnchantment = BedrockEnchantment.getByJavaIdentifier(context.id().asString()); - // TODO - description is a component. So if a hardcoded literal string is given, this will display normally on Java, - // but Geyser will attempt to lookup the literal string as translation - and will fail, displaying an empty string as enchantment name. String description = bedrockEnchantment == null ? MessageTranslator.deserializeDescription(context.session(), data) : null; return new Enchantment(context.id().asString(), effects, supportedItems, maxLevel, @@ -86,24 +81,4 @@ public record Enchantment(String identifier, } return Set.copyOf(components); // Also ensures any empty sets are consolidated } - - // TODO holder set util? - private static HolderSet readHolderSet(@Nullable Object holderSet, ToIntFunction keyIdMapping) { - if (holderSet == null) { - return new HolderSet(IntArrays.EMPTY_ARRAY); - } - - if (holderSet instanceof String stringTag) { - // Tag - if (stringTag.startsWith("#")) { - return new HolderSet(MinecraftKey.key(stringTag.substring(1))); // Remove '#' at beginning that indicates tag - } else { - return new HolderSet(new int[]{keyIdMapping.applyAsInt(MinecraftKey.key(stringTag))}); - } - } else if (holderSet instanceof List list) { - // Assume the list is a list of strings - return new HolderSet(list.stream().map(o -> (String) o).map(Key::key).mapToInt(keyIdMapping).toArray()); - } - throw new IllegalArgumentException("Holder set must either be a tag, a string ID or a list of string IDs"); - } } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ArrowItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ArrowItem.java index 4e4f1830e..b2d3737d8 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/ArrowItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/ArrowItem.java @@ -32,6 +32,7 @@ import org.geysermc.geyser.inventory.item.Potion; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.PotionContents; @@ -41,9 +42,9 @@ public class ArrowItem extends Item { } @Override - public @NonNull GeyserItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) { + public @NonNull GeyserItemStack translateToJava(GeyserSession session, @NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) { Potion potion = Potion.getByTippedArrowDamage(itemData.getDamage()); - GeyserItemStack itemStack = super.translateToJava(itemData, mapping, mappings); + GeyserItemStack itemStack = super.translateToJava(session, itemData, mapping, mappings); if (potion != null) { itemStack = Items.TIPPED_ARROW.newItemStack(itemStack.getAmount(), itemStack.getComponents()); PotionContents contents = potion.toComponent(); diff --git a/core/src/main/java/org/geysermc/geyser/item/type/CompassItem.java b/core/src/main/java/org/geysermc/geyser/item/type/CompassItem.java index 712e75a23..1c0ec0d5f 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/CompassItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/CompassItem.java @@ -43,11 +43,11 @@ public class CompassItem extends Item { } @Override - public ItemData.Builder translateToBedrock(int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) { + public ItemData.Builder translateToBedrock(GeyserSession session, int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) { if (isLodestoneCompass(components)) { - return super.translateToBedrock(count, components, mappings.getLodestoneCompass(), mappings); + return super.translateToBedrock(session, count, components, mappings.getLodestoneCompass(), mappings); } - return super.translateToBedrock(count, components, mapping, mappings); + return super.translateToBedrock(session, count, components, mapping, mappings); } @Override @@ -78,12 +78,12 @@ public class CompassItem extends Item { } @Override - public @NonNull GeyserItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) { + public @NonNull GeyserItemStack translateToJava(GeyserSession session, @NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) { if (mapping.getBedrockIdentifier().equals("minecraft:lodestone_compass")) { // Revert the entry back to the compass mapping = mappings.getStoredItems().compass(); } - return super.translateToJava(itemData, mapping, mappings); + return super.translateToJava(session, itemData, mapping, mappings); } } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FilledMapItem.java b/core/src/main/java/org/geysermc/geyser/item/type/FilledMapItem.java index e571a796a..07a0ad133 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/FilledMapItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/FilledMapItem.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.item.type; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; @@ -37,8 +38,8 @@ public class FilledMapItem extends MapItem { } @Override - public ItemData.Builder translateToBedrock(int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) { - ItemData.Builder builder = super.translateToBedrock(count, components, mapping, mappings); + public ItemData.Builder translateToBedrock(GeyserSession session, int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) { + ItemData.Builder builder = super.translateToBedrock(session, count, components, mapping, mappings); if (components == null) { // This is a fallback for maps with no nbt (Change added back in June 2020; is it needed in 2023?) //return builder.tag(NbtMap.builder().putInt("map", 0).build()); TODO if this is *still* broken, let's move it to translateComponentsToBedrock diff --git a/core/src/main/java/org/geysermc/geyser/item/type/GoatHornItem.java b/core/src/main/java/org/geysermc/geyser/item/type/GoatHornItem.java index d0e85ec52..9af07a40e 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/GoatHornItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/GoatHornItem.java @@ -28,8 +28,11 @@ package org.geysermc.geyser.item.type; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.inventory.GeyserItemStack; +import org.geysermc.geyser.inventory.item.GeyserInstrument; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.item.BedrockItemBuilder; import org.geysermc.mcprotocollib.protocol.data.game.Holder; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; @@ -41,24 +44,45 @@ public class GoatHornItem extends Item { } @Override - public ItemData.Builder translateToBedrock(int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) { - ItemData.Builder builder = super.translateToBedrock(count, components, mapping, mappings); + public ItemData.Builder translateToBedrock(GeyserSession session, int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) { + ItemData.Builder builder = super.translateToBedrock(session, count, components, mapping, mappings); if (components == null) { return builder; } - Holder instrument = components.get(DataComponentType.INSTRUMENT); - if (instrument != null && instrument.isId()) { - builder.damage(instrument.id()); + + Holder holder = components.get(DataComponentType.INSTRUMENT); + if (holder != null) { + GeyserInstrument instrument = GeyserInstrument.fromHolder(session, holder); + int bedrockId = instrument.bedrockId(); + if (bedrockId >= 0) { + builder.damage(bedrockId); + } } + return builder; } @Override - public @NonNull GeyserItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) { - GeyserItemStack itemStack = super.translateToJava(itemData, mapping, mappings); + public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) { + super.translateComponentsToBedrock(session, components, builder); + + Holder holder = components.get(DataComponentType.INSTRUMENT); + if (holder != null && components.get(DataComponentType.HIDE_TOOLTIP) == null + && components.get(DataComponentType.HIDE_ADDITIONAL_TOOLTIP) == null) { + GeyserInstrument instrument = GeyserInstrument.fromHolder(session, holder); + if (instrument.bedrockInstrument() == null) { + builder.getOrCreateLore().add(instrument.description()); + } + } + } + + @Override + public @NonNull GeyserItemStack translateToJava(GeyserSession session, @NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) { + GeyserItemStack itemStack = super.translateToJava(session, itemData, mapping, mappings); int damage = itemData.getDamage(); - itemStack.getOrCreateComponents().put(DataComponentType.INSTRUMENT, Holder.ofId(damage)); + // This could cause an issue since -1 is returned for non-vanilla goat horns + itemStack.getOrCreateComponents().put(DataComponentType.INSTRUMENT, Holder.ofId(GeyserInstrument.bedrockIdToJava(session, damage))); return itemStack; } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/Item.java b/core/src/main/java/org/geysermc/geyser/item/type/Item.java index a8a477025..249936e5a 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/Item.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/Item.java @@ -115,7 +115,7 @@ public class Item { /* Translation methods to Bedrock and back */ - public ItemData.Builder translateToBedrock(int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) { + public ItemData.Builder translateToBedrock(GeyserSession session, int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) { if (this == Items.AIR || count <= 0) { // Return, essentially, air return ItemData.builder(); @@ -130,7 +130,7 @@ public class Item { return builder; } - public @NonNull GeyserItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) { + public @NonNull GeyserItemStack translateToJava(GeyserSession session, @NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) { return GeyserItemStack.of(javaId, itemData.getCount()); } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/OminousBottleItem.java b/core/src/main/java/org/geysermc/geyser/item/type/OminousBottleItem.java index 815f71419..92a8d726d 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/OminousBottleItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/OminousBottleItem.java @@ -31,6 +31,7 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; @@ -40,8 +41,8 @@ public class OminousBottleItem extends Item { } @Override - public ItemData.Builder translateToBedrock(int count, @Nullable DataComponents components, ItemMapping mapping, ItemMappings mappings) { - var builder = super.translateToBedrock(count, components, mapping, mappings); + public ItemData.Builder translateToBedrock(GeyserSession session, int count, @Nullable DataComponents components, ItemMapping mapping, ItemMappings mappings) { + var builder = super.translateToBedrock(session, count, components, mapping, mappings); if (components == null) { // Level 1 ominous bottle is null components - Java 1.21. return builder; @@ -54,9 +55,9 @@ public class OminousBottleItem extends Item { } @Override - public @NonNull GeyserItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) { + public @NonNull GeyserItemStack translateToJava(GeyserSession session, @NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) { // This item can be pulled from the creative inventory with amplifiers. - GeyserItemStack itemStack = super.translateToJava(itemData, mapping, mappings); + GeyserItemStack itemStack = super.translateToJava(session, itemData, mapping, mappings); int damage = itemData.getDamage(); if (damage == 0) { return itemStack; diff --git a/core/src/main/java/org/geysermc/geyser/item/type/PotionItem.java b/core/src/main/java/org/geysermc/geyser/item/type/PotionItem.java index f8fe2b4ee..89e60b325 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/PotionItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/PotionItem.java @@ -33,6 +33,7 @@ import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.item.Potion; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.item.CustomItemTranslator; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; @@ -44,8 +45,8 @@ public class PotionItem extends Item { } @Override - public ItemData.Builder translateToBedrock(int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) { - if (components == null) return super.translateToBedrock(count, components, mapping, mappings); + public ItemData.Builder translateToBedrock(GeyserSession session, int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) { + if (components == null) return super.translateToBedrock(session, count, components, mapping, mappings); PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS); if (potionContents != null) { ItemDefinition customItemDefinition = CustomItemTranslator.getCustomItem(components, mapping); @@ -64,13 +65,13 @@ public class PotionItem extends Item { .count(count); } } - return super.translateToBedrock(count, components, mapping, mappings); + return super.translateToBedrock(session, count, components, mapping, mappings); } @Override - public @NonNull GeyserItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) { + public @NonNull GeyserItemStack translateToJava(GeyserSession session, @NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) { Potion potion = Potion.getByBedrockId(itemData.getDamage()); - GeyserItemStack itemStack = super.translateToJava(itemData, mapping, mappings); + GeyserItemStack itemStack = super.translateToJava(session, itemData, mapping, mappings); if (potion != null) { itemStack.getOrCreateComponents().put(DataComponentType.POTION_CONTENTS, potion.toComponent()); } diff --git a/core/src/main/java/org/geysermc/geyser/item/type/TippedArrowItem.java b/core/src/main/java/org/geysermc/geyser/item/type/TippedArrowItem.java index d9e58eaf9..09e4ee21f 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/TippedArrowItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/TippedArrowItem.java @@ -30,6 +30,7 @@ import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.item.Potion; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.PotionContents; @@ -40,7 +41,7 @@ public class TippedArrowItem extends ArrowItem { } @Override - public ItemData.Builder translateToBedrock(int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) { + public ItemData.Builder translateToBedrock(GeyserSession session, int count, DataComponents components, ItemMapping mapping, ItemMappings mappings) { if (components != null) { PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS); if (potionContents != null) { @@ -54,6 +55,6 @@ public class TippedArrowItem extends ArrowItem { GeyserImpl.getInstance().getLogger().debug("Unknown Java potion (tipped arrow): " + potionContents.getPotionId()); } } - return super.translateToBedrock(count, components, mapping, mappings); + return super.translateToBedrock(session, count, components, mapping, mappings); } } diff --git a/core/src/main/java/org/geysermc/geyser/level/JukeboxSong.java b/core/src/main/java/org/geysermc/geyser/level/JukeboxSong.java index 86d66e209..1bed4099a 100644 --- a/core/src/main/java/org/geysermc/geyser/level/JukeboxSong.java +++ b/core/src/main/java/org/geysermc/geyser/level/JukeboxSong.java @@ -26,24 +26,15 @@ package org.geysermc.geyser.level; import org.cloudburstmc.nbt.NbtMap; -import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.session.cache.registry.RegistryEntryContext; import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.geyser.util.SoundUtils; public record JukeboxSong(String soundEvent, String description) { public static JukeboxSong read(RegistryEntryContext context) { NbtMap data = context.data(); - Object soundEventObject = data.get("sound_event"); - String soundEvent; - if (soundEventObject instanceof NbtMap map) { - soundEvent = map.getString("sound_id"); - } else if (soundEventObject instanceof String string) { - soundEvent = string; - } else { - soundEvent = ""; - GeyserImpl.getInstance().getLogger().debug("Sound event for " + context.id() + " was of an unexpected type! Expected string or NBT map, got " + soundEventObject); - } + String soundEvent = SoundUtils.readSoundEvent(data, "jukebox song " + context.id()); String description = MessageTranslator.deserializeDescription(context.session(), data); return new JukeboxSong(soundEvent, description); } diff --git a/core/src/main/java/org/geysermc/geyser/level/block/Blocks.java b/core/src/main/java/org/geysermc/geyser/level/block/Blocks.java index 735c1f6c4..5db38c559 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/Blocks.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/Blocks.java @@ -49,11 +49,11 @@ public final class Blocks { public static final Block ANDESITE = register(new Block("andesite", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); public static final Block POLISHED_ANDESITE = register(new Block("polished_andesite", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); public static final Block GRASS_BLOCK = register(new Block("grass_block", builder().destroyTime(0.6f) - .booleanState(SNOWY))); + .booleanState(SNOWY))); public static final Block DIRT = register(new Block("dirt", builder().destroyTime(0.5f))); public static final Block COARSE_DIRT = register(new Block("coarse_dirt", builder().destroyTime(0.5f))); public static final Block PODZOL = register(new Block("podzol", builder().destroyTime(0.5f) - .booleanState(SNOWY))); + .booleanState(SNOWY))); public static final Block COBBLESTONE = register(new Block("cobblestone", builder().requiresCorrectToolForDrops().destroyTime(2.0f))); public static final Block OAK_PLANKS = register(new Block("oak_planks", builder().destroyTime(2.0f))); public static final Block SPRUCE_PLANKS = register(new Block("spruce_planks", builder().destroyTime(2.0f))); @@ -62,40 +62,45 @@ public final class Blocks { public static final Block ACACIA_PLANKS = register(new Block("acacia_planks", builder().destroyTime(2.0f))); public static final Block CHERRY_PLANKS = register(new Block("cherry_planks", builder().destroyTime(2.0f))); public static final Block DARK_OAK_PLANKS = register(new Block("dark_oak_planks", builder().destroyTime(2.0f))); + public static final Block PALE_OAK_WOOD = register(new Block("pale_oak_wood", builder().destroyTime(2.0f) + .enumState(AXIS, Axis.VALUES))); + public static final Block PALE_OAK_PLANKS = register(new Block("pale_oak_planks", builder().destroyTime(2.0f))); public static final Block MANGROVE_PLANKS = register(new Block("mangrove_planks", builder().destroyTime(2.0f))); public static final Block BAMBOO_PLANKS = register(new Block("bamboo_planks", builder().destroyTime(2.0f))); public static final Block BAMBOO_MOSAIC = register(new Block("bamboo_mosaic", builder().destroyTime(2.0f))); public static final Block OAK_SAPLING = register(new Block("oak_sapling", builder().pushReaction(PistonBehavior.DESTROY) - .intState(STAGE))); + .intState(STAGE))); public static final Block SPRUCE_SAPLING = register(new Block("spruce_sapling", builder().pushReaction(PistonBehavior.DESTROY) - .intState(STAGE))); + .intState(STAGE))); public static final Block BIRCH_SAPLING = register(new Block("birch_sapling", builder().pushReaction(PistonBehavior.DESTROY) - .intState(STAGE))); + .intState(STAGE))); public static final Block JUNGLE_SAPLING = register(new Block("jungle_sapling", builder().pushReaction(PistonBehavior.DESTROY) - .intState(STAGE))); + .intState(STAGE))); public static final Block ACACIA_SAPLING = register(new Block("acacia_sapling", builder().pushReaction(PistonBehavior.DESTROY) - .intState(STAGE))); + .intState(STAGE))); public static final Block CHERRY_SAPLING = register(new Block("cherry_sapling", builder().pushReaction(PistonBehavior.DESTROY) - .intState(STAGE))); + .intState(STAGE))); public static final Block DARK_OAK_SAPLING = register(new Block("dark_oak_sapling", builder().pushReaction(PistonBehavior.DESTROY) - .intState(STAGE))); + .intState(STAGE))); + public static final Block PALE_OAK_SAPLING = register(new Block("pale_oak_sapling", builder().pushReaction(PistonBehavior.DESTROY) + .intState(STAGE))); public static final Block MANGROVE_PROPAGULE = register(new Block("mangrove_propagule", builder().pushReaction(PistonBehavior.DESTROY) - .intState(AGE_4) - .booleanState(HANGING) - .intState(STAGE) - .booleanState(WATERLOGGED))); + .intState(AGE_4) + .booleanState(HANGING) + .intState(STAGE) + .booleanState(WATERLOGGED))); public static final Block BEDROCK = register(new Block("bedrock", builder().destroyTime(-1.0f))); public static final Block WATER = register(new WaterBlock("water", builder().destroyTime(100.0f).pushReaction(PistonBehavior.DESTROY) - .intState(LEVEL))); + .intState(LEVEL))); public static final Block LAVA = register(new Block("lava", builder().destroyTime(100.0f).pushReaction(PistonBehavior.DESTROY) - .intState(LEVEL))); + .intState(LEVEL))); public static final Block SAND = register(new Block("sand", builder().destroyTime(0.5f))); public static final Block SUSPICIOUS_SAND = register(new Block("suspicious_sand", builder().setBlockEntity(BlockEntityType.BRUSHABLE_BLOCK).destroyTime(0.25f).pushReaction(PistonBehavior.DESTROY) - .intState(DUSTED))); + .intState(DUSTED))); public static final Block RED_SAND = register(new Block("red_sand", builder().destroyTime(0.5f))); public static final Block GRAVEL = register(new Block("gravel", builder().destroyTime(0.6f))); public static final Block SUSPICIOUS_GRAVEL = register(new Block("suspicious_gravel", builder().setBlockEntity(BlockEntityType.BRUSHABLE_BLOCK).destroyTime(0.25f).pushReaction(PistonBehavior.DESTROY) - .intState(DUSTED))); + .intState(DUSTED))); public static final Block GOLD_ORE = register(new Block("gold_ore", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); public static final Block DEEPSLATE_GOLD_ORE = register(new Block("deepslate_gold_ore", builder().requiresCorrectToolForDrops().destroyTime(4.5f))); public static final Block IRON_ORE = register(new Block("iron_ore", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); @@ -104,117 +109,127 @@ public final class Blocks { public static final Block DEEPSLATE_COAL_ORE = register(new Block("deepslate_coal_ore", builder().requiresCorrectToolForDrops().destroyTime(4.5f))); public static final Block NETHER_GOLD_ORE = register(new Block("nether_gold_ore", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); public static final Block OAK_LOG = register(new Block("oak_log", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block SPRUCE_LOG = register(new Block("spruce_log", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block BIRCH_LOG = register(new Block("birch_log", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block JUNGLE_LOG = register(new Block("jungle_log", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block ACACIA_LOG = register(new Block("acacia_log", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block CHERRY_LOG = register(new Block("cherry_log", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block DARK_OAK_LOG = register(new Block("dark_oak_log", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); + public static final Block PALE_OAK_LOG = register(new Block("pale_oak_log", builder().destroyTime(2.0f) + .enumState(AXIS, Axis.VALUES))); public static final Block MANGROVE_LOG = register(new Block("mangrove_log", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block MANGROVE_ROOTS = register(new Block("mangrove_roots", builder().destroyTime(0.7f) - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block MUDDY_MANGROVE_ROOTS = register(new Block("muddy_mangrove_roots", builder().destroyTime(0.7f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block BAMBOO_BLOCK = register(new Block("bamboo_block", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block STRIPPED_SPRUCE_LOG = register(new Block("stripped_spruce_log", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block STRIPPED_BIRCH_LOG = register(new Block("stripped_birch_log", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block STRIPPED_JUNGLE_LOG = register(new Block("stripped_jungle_log", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block STRIPPED_ACACIA_LOG = register(new Block("stripped_acacia_log", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block STRIPPED_CHERRY_LOG = register(new Block("stripped_cherry_log", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block STRIPPED_DARK_OAK_LOG = register(new Block("stripped_dark_oak_log", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); + public static final Block STRIPPED_PALE_OAK_LOG = register(new Block("stripped_pale_oak_log", builder().destroyTime(2.0f) + .enumState(AXIS, Axis.VALUES))); public static final Block STRIPPED_OAK_LOG = register(new Block("stripped_oak_log", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block STRIPPED_MANGROVE_LOG = register(new Block("stripped_mangrove_log", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block STRIPPED_BAMBOO_BLOCK = register(new Block("stripped_bamboo_block", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block OAK_WOOD = register(new Block("oak_wood", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block SPRUCE_WOOD = register(new Block("spruce_wood", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block BIRCH_WOOD = register(new Block("birch_wood", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block JUNGLE_WOOD = register(new Block("jungle_wood", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block ACACIA_WOOD = register(new Block("acacia_wood", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block CHERRY_WOOD = register(new Block("cherry_wood", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block DARK_OAK_WOOD = register(new Block("dark_oak_wood", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block MANGROVE_WOOD = register(new Block("mangrove_wood", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block STRIPPED_OAK_WOOD = register(new Block("stripped_oak_wood", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block STRIPPED_SPRUCE_WOOD = register(new Block("stripped_spruce_wood", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block STRIPPED_BIRCH_WOOD = register(new Block("stripped_birch_wood", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block STRIPPED_JUNGLE_WOOD = register(new Block("stripped_jungle_wood", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block STRIPPED_ACACIA_WOOD = register(new Block("stripped_acacia_wood", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block STRIPPED_CHERRY_WOOD = register(new Block("stripped_cherry_wood", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block STRIPPED_DARK_OAK_WOOD = register(new Block("stripped_dark_oak_wood", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); + public static final Block STRIPPED_PALE_OAK_WOOD = register(new Block("stripped_pale_oak_wood", builder().destroyTime(2.0f) + .enumState(AXIS, Axis.VALUES))); public static final Block STRIPPED_MANGROVE_WOOD = register(new Block("stripped_mangrove_wood", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block OAK_LEAVES = register(new Block("oak_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .intState(DISTANCE) - .booleanState(PERSISTENT) - .booleanState(WATERLOGGED))); + .intState(DISTANCE) + .booleanState(PERSISTENT) + .booleanState(WATERLOGGED))); public static final Block SPRUCE_LEAVES = register(new Block("spruce_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .intState(DISTANCE) - .booleanState(PERSISTENT) - .booleanState(WATERLOGGED))); + .intState(DISTANCE) + .booleanState(PERSISTENT) + .booleanState(WATERLOGGED))); public static final Block BIRCH_LEAVES = register(new Block("birch_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .intState(DISTANCE) - .booleanState(PERSISTENT) - .booleanState(WATERLOGGED))); + .intState(DISTANCE) + .booleanState(PERSISTENT) + .booleanState(WATERLOGGED))); public static final Block JUNGLE_LEAVES = register(new Block("jungle_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .intState(DISTANCE) - .booleanState(PERSISTENT) - .booleanState(WATERLOGGED))); + .intState(DISTANCE) + .booleanState(PERSISTENT) + .booleanState(WATERLOGGED))); public static final Block ACACIA_LEAVES = register(new Block("acacia_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .intState(DISTANCE) - .booleanState(PERSISTENT) - .booleanState(WATERLOGGED))); + .intState(DISTANCE) + .booleanState(PERSISTENT) + .booleanState(WATERLOGGED))); public static final Block CHERRY_LEAVES = register(new Block("cherry_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .intState(DISTANCE) - .booleanState(PERSISTENT) - .booleanState(WATERLOGGED))); + .intState(DISTANCE) + .booleanState(PERSISTENT) + .booleanState(WATERLOGGED))); public static final Block DARK_OAK_LEAVES = register(new Block("dark_oak_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .intState(DISTANCE) - .booleanState(PERSISTENT) - .booleanState(WATERLOGGED))); + .intState(DISTANCE) + .booleanState(PERSISTENT) + .booleanState(WATERLOGGED))); + public static final Block PALE_OAK_LEAVES = register(new Block("pale_oak_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) + .intState(DISTANCE) + .booleanState(PERSISTENT) + .booleanState(WATERLOGGED))); public static final Block MANGROVE_LEAVES = register(new Block("mangrove_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .intState(DISTANCE) - .booleanState(PERSISTENT) - .booleanState(WATERLOGGED))); + .intState(DISTANCE) + .booleanState(PERSISTENT) + .booleanState(WATERLOGGED))); public static final Block AZALEA_LEAVES = register(new Block("azalea_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .intState(DISTANCE) - .booleanState(PERSISTENT) - .booleanState(WATERLOGGED))); + .intState(DISTANCE) + .booleanState(PERSISTENT) + .booleanState(WATERLOGGED))); public static final Block FLOWERING_AZALEA_LEAVES = register(new Block("flowering_azalea_leaves", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .intState(DISTANCE) - .booleanState(PERSISTENT) - .booleanState(WATERLOGGED))); + .intState(DISTANCE) + .booleanState(PERSISTENT) + .booleanState(WATERLOGGED))); public static final Block SPONGE = register(new Block("sponge", builder().destroyTime(0.6f))); public static final Block WET_SPONGE = register(new Block("wet_sponge", builder().destroyTime(0.6f))); public static final Block GLASS = register(new Block("glass", builder().destroyTime(0.3f))); @@ -222,104 +237,104 @@ public final class Blocks { public static final Block DEEPSLATE_LAPIS_ORE = register(new Block("deepslate_lapis_ore", builder().requiresCorrectToolForDrops().destroyTime(4.5f))); public static final Block LAPIS_BLOCK = register(new Block("lapis_block", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); public static final Block DISPENSER = register(new Block("dispenser", builder().setBlockEntity(BlockEntityType.DISPENSER).requiresCorrectToolForDrops().destroyTime(3.5f) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) - .booleanState(TRIGGERED))); + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) + .booleanState(TRIGGERED))); public static final Block SANDSTONE = register(new Block("sandstone", builder().requiresCorrectToolForDrops().destroyTime(0.8f))); public static final Block CHISELED_SANDSTONE = register(new Block("chiseled_sandstone", builder().requiresCorrectToolForDrops().destroyTime(0.8f))); public static final Block CUT_SANDSTONE = register(new Block("cut_sandstone", builder().requiresCorrectToolForDrops().destroyTime(0.8f))); public static final Block NOTE_BLOCK = register(new Block("note_block", builder().destroyTime(0.8f) - .enumState(NOTEBLOCK_INSTRUMENT) - .intState(NOTE) - .booleanState(POWERED))); + .enumState(NOTEBLOCK_INSTRUMENT) + .intState(NOTE) + .booleanState(POWERED))); public static final Block WHITE_BED = register(new BedBlock("white_bed", 0, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(OCCUPIED) - .enumState(BED_PART))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART))); public static final Block ORANGE_BED = register(new BedBlock("orange_bed", 1, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(OCCUPIED) - .enumState(BED_PART))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART))); public static final Block MAGENTA_BED = register(new BedBlock("magenta_bed", 2, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(OCCUPIED) - .enumState(BED_PART))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART))); public static final Block LIGHT_BLUE_BED = register(new BedBlock("light_blue_bed", 3, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(OCCUPIED) - .enumState(BED_PART))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART))); public static final Block YELLOW_BED = register(new BedBlock("yellow_bed", 4, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(OCCUPIED) - .enumState(BED_PART))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART))); public static final Block LIME_BED = register(new BedBlock("lime_bed", 5, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(OCCUPIED) - .enumState(BED_PART))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART))); public static final Block PINK_BED = register(new BedBlock("pink_bed", 6, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(OCCUPIED) - .enumState(BED_PART))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART))); public static final Block GRAY_BED = register(new BedBlock("gray_bed", 7, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(OCCUPIED) - .enumState(BED_PART))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART))); public static final Block LIGHT_GRAY_BED = register(new BedBlock("light_gray_bed", 8, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(OCCUPIED) - .enumState(BED_PART))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART))); public static final Block CYAN_BED = register(new BedBlock("cyan_bed", 9, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(OCCUPIED) - .enumState(BED_PART))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART))); public static final Block PURPLE_BED = register(new BedBlock("purple_bed", 10, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(OCCUPIED) - .enumState(BED_PART))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART))); public static final Block BLUE_BED = register(new BedBlock("blue_bed", 11, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(OCCUPIED) - .enumState(BED_PART))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART))); public static final Block BROWN_BED = register(new BedBlock("brown_bed", 12, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(OCCUPIED) - .enumState(BED_PART))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART))); public static final Block GREEN_BED = register(new BedBlock("green_bed", 13, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(OCCUPIED) - .enumState(BED_PART))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART))); public static final Block RED_BED = register(new BedBlock("red_bed", 14, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(OCCUPIED) - .enumState(BED_PART))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART))); public static final Block BLACK_BED = register(new BedBlock("black_bed", 15, builder().setBlockEntity(BlockEntityType.BED).destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(OCCUPIED) - .enumState(BED_PART))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OCCUPIED) + .enumState(BED_PART))); public static final Block POWERED_RAIL = register(new Block("powered_rail", builder().destroyTime(0.7f) - .booleanState(POWERED) - .enumState(RAIL_SHAPE_STRAIGHT) - .booleanState(WATERLOGGED))); + .booleanState(POWERED) + .enumState(RAIL_SHAPE_STRAIGHT) + .booleanState(WATERLOGGED))); public static final Block DETECTOR_RAIL = register(new Block("detector_rail", builder().destroyTime(0.7f) - .booleanState(POWERED) - .enumState(RAIL_SHAPE_STRAIGHT) - .booleanState(WATERLOGGED))); + .booleanState(POWERED) + .enumState(RAIL_SHAPE_STRAIGHT) + .booleanState(WATERLOGGED))); public static final Block STICKY_PISTON = register(new PistonBlock("sticky_piston", builder().destroyTime(1.5f).pushReaction(PistonBehavior.BLOCK) - .booleanState(EXTENDED) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); + .booleanState(EXTENDED) + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); public static final Block COBWEB = register(new Block("cobweb", builder().requiresCorrectToolForDrops().destroyTime(4.0f).pushReaction(PistonBehavior.DESTROY))); public static final Block SHORT_GRASS = register(new Block("short_grass", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block FERN = register(new Block("fern", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block DEAD_BUSH = register(new Block("dead_bush", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block SEAGRASS = register(new Block("seagrass", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block TALL_SEAGRASS = register(new Block("tall_seagrass", builder().pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.SEAGRASS) - .enumState(DOUBLE_BLOCK_HALF))); + .enumState(DOUBLE_BLOCK_HALF))); public static final Block PISTON = register(new PistonBlock("piston", builder().destroyTime(1.5f).pushReaction(PistonBehavior.BLOCK) - .booleanState(EXTENDED) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); + .booleanState(EXTENDED) + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); public static final Block PISTON_HEAD = register(new PistonHeadBlock("piston_head", builder().destroyTime(1.5f).pushReaction(PistonBehavior.BLOCK) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) - .booleanState(SHORT) - .enumState(PISTON_TYPE))); + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) + .booleanState(SHORT) + .enumState(PISTON_TYPE))); public static final Block WHITE_WOOL = register(new Block("white_wool", builder().destroyTime(0.8f))); public static final Block ORANGE_WOOL = register(new Block("orange_wool", builder().destroyTime(0.8f))); public static final Block MAGENTA_WOOL = register(new Block("magenta_wool", builder().destroyTime(0.8f))); @@ -337,8 +352,8 @@ public final class Blocks { public static final Block RED_WOOL = register(new Block("red_wool", builder().destroyTime(0.8f))); public static final Block BLACK_WOOL = register(new Block("black_wool", builder().destroyTime(0.8f))); public static final Block MOVING_PISTON = register(new MovingPistonBlock("moving_piston", builder().setBlockEntity(BlockEntityType.PISTON).destroyTime(-1.0f).pushReaction(PistonBehavior.BLOCK) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) - .enumState(PISTON_TYPE))); + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) + .enumState(PISTON_TYPE))); public static final Block DANDELION = register(new Block("dandelion", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block TORCHFLOWER = register(new Block("torchflower", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block POPPY = register(new Block("poppy", builder().pushReaction(PistonBehavior.DESTROY))); @@ -359,288 +374,306 @@ public final class Blocks { public static final Block IRON_BLOCK = register(new Block("iron_block", builder().requiresCorrectToolForDrops().destroyTime(5.0f))); public static final Block BRICKS = register(new Block("bricks", builder().requiresCorrectToolForDrops().destroyTime(2.0f))); public static final Block TNT = register(new Block("tnt", builder() - .booleanState(UNSTABLE))); + .booleanState(UNSTABLE))); public static final Block BOOKSHELF = register(new Block("bookshelf", builder().destroyTime(1.5f))); public static final Block CHISELED_BOOKSHELF = register(new Block("chiseled_bookshelf", builder().setBlockEntity(BlockEntityType.CHISELED_BOOKSHELF).destroyTime(1.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(CHISELED_BOOKSHELF_SLOT_0_OCCUPIED) - .booleanState(CHISELED_BOOKSHELF_SLOT_1_OCCUPIED) - .booleanState(CHISELED_BOOKSHELF_SLOT_2_OCCUPIED) - .booleanState(CHISELED_BOOKSHELF_SLOT_3_OCCUPIED) - .booleanState(CHISELED_BOOKSHELF_SLOT_4_OCCUPIED) - .booleanState(CHISELED_BOOKSHELF_SLOT_5_OCCUPIED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(CHISELED_BOOKSHELF_SLOT_0_OCCUPIED) + .booleanState(CHISELED_BOOKSHELF_SLOT_1_OCCUPIED) + .booleanState(CHISELED_BOOKSHELF_SLOT_2_OCCUPIED) + .booleanState(CHISELED_BOOKSHELF_SLOT_3_OCCUPIED) + .booleanState(CHISELED_BOOKSHELF_SLOT_4_OCCUPIED) + .booleanState(CHISELED_BOOKSHELF_SLOT_5_OCCUPIED))); public static final Block MOSSY_COBBLESTONE = register(new Block("mossy_cobblestone", builder().requiresCorrectToolForDrops().destroyTime(2.0f))); public static final Block OBSIDIAN = register(new Block("obsidian", builder().requiresCorrectToolForDrops().destroyTime(50.0f))); public static final Block TORCH = register(new Block("torch", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block WALL_TORCH = register(new Block("wall_torch", builder().pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block FIRE = register(new Block("fire", builder().pushReaction(PistonBehavior.DESTROY) - .intState(AGE_15) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(UP) - .booleanState(WEST))); + .intState(AGE_15) + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(UP) + .booleanState(WEST))); public static final Block SOUL_FIRE = register(new Block("soul_fire", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block SPAWNER = register(new SpawnerBlock("spawner", builder().setBlockEntity(BlockEntityType.MOB_SPAWNER).requiresCorrectToolForDrops().destroyTime(5.0f))); + public static final Block CREAKING_HEART = register(new Block("creaking_heart", builder().setBlockEntity(BlockEntityType.CREAKING_HEART).destroyTime(5.0f) + .enumState(AXIS, Axis.VALUES) + .enumState(CREAKING))); public static final Block OAK_STAIRS = register(new Block("oak_stairs", builder().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block CHEST = register(new ChestBlock("chest", builder().setBlockEntity(BlockEntityType.CHEST).destroyTime(2.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(CHEST_TYPE, ChestType.VALUES) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(CHEST_TYPE, ChestType.VALUES) + .booleanState(WATERLOGGED))); public static final Block REDSTONE_WIRE = register(new Block("redstone_wire", builder().pushReaction(PistonBehavior.DESTROY) - .enumState(EAST_REDSTONE) - .enumState(NORTH_REDSTONE) - .intState(POWER) - .enumState(SOUTH_REDSTONE) - .enumState(WEST_REDSTONE))); + .enumState(EAST_REDSTONE) + .enumState(NORTH_REDSTONE) + .intState(POWER) + .enumState(SOUTH_REDSTONE) + .enumState(WEST_REDSTONE))); public static final Block DIAMOND_ORE = register(new Block("diamond_ore", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); public static final Block DEEPSLATE_DIAMOND_ORE = register(new Block("deepslate_diamond_ore", builder().requiresCorrectToolForDrops().destroyTime(4.5f))); public static final Block DIAMOND_BLOCK = register(new Block("diamond_block", builder().requiresCorrectToolForDrops().destroyTime(5.0f))); public static final Block CRAFTING_TABLE = register(new Block("crafting_table", builder().destroyTime(2.5f))); public static final Block WHEAT = register(new Block("wheat", builder().pushReaction(PistonBehavior.DESTROY) - .intState(AGE_7))); + .intState(AGE_7))); public static final Block FARMLAND = register(new Block("farmland", builder().destroyTime(0.6f) - .intState(MOISTURE))); + .intState(MOISTURE))); public static final Block FURNACE = register(new FurnaceBlock("furnace", builder().setBlockEntity(BlockEntityType.FURNACE).requiresCorrectToolForDrops().destroyTime(3.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(LIT))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(LIT))); public static final Block OAK_SIGN = register(new Block("oak_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) - .intState(ROTATION_16) - .booleanState(WATERLOGGED))); + .intState(ROTATION_16) + .booleanState(WATERLOGGED))); public static final Block SPRUCE_SIGN = register(new Block("spruce_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) - .intState(ROTATION_16) - .booleanState(WATERLOGGED))); + .intState(ROTATION_16) + .booleanState(WATERLOGGED))); public static final Block BIRCH_SIGN = register(new Block("birch_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) - .intState(ROTATION_16) - .booleanState(WATERLOGGED))); + .intState(ROTATION_16) + .booleanState(WATERLOGGED))); public static final Block ACACIA_SIGN = register(new Block("acacia_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) - .intState(ROTATION_16) - .booleanState(WATERLOGGED))); + .intState(ROTATION_16) + .booleanState(WATERLOGGED))); public static final Block CHERRY_SIGN = register(new Block("cherry_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) - .intState(ROTATION_16) - .booleanState(WATERLOGGED))); + .intState(ROTATION_16) + .booleanState(WATERLOGGED))); public static final Block JUNGLE_SIGN = register(new Block("jungle_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) - .intState(ROTATION_16) - .booleanState(WATERLOGGED))); + .intState(ROTATION_16) + .booleanState(WATERLOGGED))); public static final Block DARK_OAK_SIGN = register(new Block("dark_oak_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) - .intState(ROTATION_16) - .booleanState(WATERLOGGED))); + .intState(ROTATION_16) + .booleanState(WATERLOGGED))); + public static final Block PALE_OAK_SIGN = register(new Block("pale_oak_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) + .intState(ROTATION_16) + .booleanState(WATERLOGGED))); public static final Block MANGROVE_SIGN = register(new Block("mangrove_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) - .intState(ROTATION_16) - .booleanState(WATERLOGGED))); + .intState(ROTATION_16) + .booleanState(WATERLOGGED))); public static final Block BAMBOO_SIGN = register(new Block("bamboo_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) - .intState(ROTATION_16) - .booleanState(WATERLOGGED))); + .intState(ROTATION_16) + .booleanState(WATERLOGGED))); public static final Block OAK_DOOR = register(new DoorBlock("oak_door", builder().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(DOUBLE_BLOCK_HALF) - .enumState(DOOR_HINGE) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF) + .enumState(DOOR_HINGE) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block LADDER = register(new Block("ladder", builder().destroyTime(0.4f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block RAIL = register(new Block("rail", builder().destroyTime(0.7f) - .enumState(RAIL_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(RAIL_SHAPE) + .booleanState(WATERLOGGED))); public static final Block COBBLESTONE_STAIRS = register(new Block("cobblestone_stairs", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block OAK_WALL_SIGN = register(new Block("oak_wall_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block SPRUCE_WALL_SIGN = register(new Block("spruce_wall_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block BIRCH_WALL_SIGN = register(new Block("birch_wall_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block ACACIA_WALL_SIGN = register(new Block("acacia_wall_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block CHERRY_WALL_SIGN = register(new Block("cherry_wall_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block JUNGLE_WALL_SIGN = register(new Block("jungle_wall_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block DARK_OAK_WALL_SIGN = register(new Block("dark_oak_wall_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); + public static final Block PALE_OAK_WALL_SIGN = register(new Block("pale_oak_wall_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block MANGROVE_WALL_SIGN = register(new Block("mangrove_wall_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block BAMBOO_WALL_SIGN = register(new Block("bamboo_wall_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block OAK_HANGING_SIGN = register(new Block("oak_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f) - .booleanState(ATTACHED) - .intState(ROTATION_16) - .booleanState(WATERLOGGED))); + .booleanState(ATTACHED) + .intState(ROTATION_16) + .booleanState(WATERLOGGED))); public static final Block SPRUCE_HANGING_SIGN = register(new Block("spruce_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f) - .booleanState(ATTACHED) - .intState(ROTATION_16) - .booleanState(WATERLOGGED))); + .booleanState(ATTACHED) + .intState(ROTATION_16) + .booleanState(WATERLOGGED))); public static final Block BIRCH_HANGING_SIGN = register(new Block("birch_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f) - .booleanState(ATTACHED) - .intState(ROTATION_16) - .booleanState(WATERLOGGED))); + .booleanState(ATTACHED) + .intState(ROTATION_16) + .booleanState(WATERLOGGED))); public static final Block ACACIA_HANGING_SIGN = register(new Block("acacia_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f) - .booleanState(ATTACHED) - .intState(ROTATION_16) - .booleanState(WATERLOGGED))); + .booleanState(ATTACHED) + .intState(ROTATION_16) + .booleanState(WATERLOGGED))); public static final Block CHERRY_HANGING_SIGN = register(new Block("cherry_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f) - .booleanState(ATTACHED) - .intState(ROTATION_16) - .booleanState(WATERLOGGED))); + .booleanState(ATTACHED) + .intState(ROTATION_16) + .booleanState(WATERLOGGED))); public static final Block JUNGLE_HANGING_SIGN = register(new Block("jungle_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f) - .booleanState(ATTACHED) - .intState(ROTATION_16) - .booleanState(WATERLOGGED))); + .booleanState(ATTACHED) + .intState(ROTATION_16) + .booleanState(WATERLOGGED))); public static final Block DARK_OAK_HANGING_SIGN = register(new Block("dark_oak_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f) - .booleanState(ATTACHED) - .intState(ROTATION_16) - .booleanState(WATERLOGGED))); + .booleanState(ATTACHED) + .intState(ROTATION_16) + .booleanState(WATERLOGGED))); + public static final Block PALE_OAK_HANGING_SIGN = register(new Block("pale_oak_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f) + .booleanState(ATTACHED) + .intState(ROTATION_16) + .booleanState(WATERLOGGED))); public static final Block CRIMSON_HANGING_SIGN = register(new Block("crimson_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f) - .booleanState(ATTACHED) - .intState(ROTATION_16) - .booleanState(WATERLOGGED))); + .booleanState(ATTACHED) + .intState(ROTATION_16) + .booleanState(WATERLOGGED))); public static final Block WARPED_HANGING_SIGN = register(new Block("warped_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f) - .booleanState(ATTACHED) - .intState(ROTATION_16) - .booleanState(WATERLOGGED))); + .booleanState(ATTACHED) + .intState(ROTATION_16) + .booleanState(WATERLOGGED))); public static final Block MANGROVE_HANGING_SIGN = register(new Block("mangrove_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f) - .booleanState(ATTACHED) - .intState(ROTATION_16) - .booleanState(WATERLOGGED))); + .booleanState(ATTACHED) + .intState(ROTATION_16) + .booleanState(WATERLOGGED))); public static final Block BAMBOO_HANGING_SIGN = register(new Block("bamboo_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f) - .booleanState(ATTACHED) - .intState(ROTATION_16) - .booleanState(WATERLOGGED))); + .booleanState(ATTACHED) + .intState(ROTATION_16) + .booleanState(WATERLOGGED))); public static final Block OAK_WALL_HANGING_SIGN = register(new Block("oak_wall_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block SPRUCE_WALL_HANGING_SIGN = register(new Block("spruce_wall_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block BIRCH_WALL_HANGING_SIGN = register(new Block("birch_wall_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block ACACIA_WALL_HANGING_SIGN = register(new Block("acacia_wall_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block CHERRY_WALL_HANGING_SIGN = register(new Block("cherry_wall_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block JUNGLE_WALL_HANGING_SIGN = register(new Block("jungle_wall_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block DARK_OAK_WALL_HANGING_SIGN = register(new Block("dark_oak_wall_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); + public static final Block PALE_OAK_WALL_HANGING_SIGN = register(new Block("pale_oak_wall_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block MANGROVE_WALL_HANGING_SIGN = register(new Block("mangrove_wall_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block CRIMSON_WALL_HANGING_SIGN = register(new Block("crimson_wall_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block WARPED_WALL_HANGING_SIGN = register(new Block("warped_wall_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block BAMBOO_WALL_HANGING_SIGN = register(new Block("bamboo_wall_hanging_sign", builder().setBlockEntity(BlockEntityType.HANGING_SIGN).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block LEVER = register(new Block("lever", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .enumState(ATTACH_FACE) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(POWERED))); + .enumState(ATTACH_FACE) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); public static final Block STONE_PRESSURE_PLATE = register(new Block("stone_pressure_plate", builder().requiresCorrectToolForDrops().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .booleanState(POWERED))); + .booleanState(POWERED))); public static final Block IRON_DOOR = register(new DoorBlock("iron_door", builder().requiresCorrectToolForDrops().destroyTime(5.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(DOUBLE_BLOCK_HALF) - .enumState(DOOR_HINGE) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF) + .enumState(DOOR_HINGE) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block OAK_PRESSURE_PLATE = register(new Block("oak_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .booleanState(POWERED))); + .booleanState(POWERED))); public static final Block SPRUCE_PRESSURE_PLATE = register(new Block("spruce_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .booleanState(POWERED))); + .booleanState(POWERED))); public static final Block BIRCH_PRESSURE_PLATE = register(new Block("birch_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .booleanState(POWERED))); + .booleanState(POWERED))); public static final Block JUNGLE_PRESSURE_PLATE = register(new Block("jungle_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .booleanState(POWERED))); + .booleanState(POWERED))); public static final Block ACACIA_PRESSURE_PLATE = register(new Block("acacia_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .booleanState(POWERED))); + .booleanState(POWERED))); public static final Block CHERRY_PRESSURE_PLATE = register(new Block("cherry_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .booleanState(POWERED))); + .booleanState(POWERED))); public static final Block DARK_OAK_PRESSURE_PLATE = register(new Block("dark_oak_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .booleanState(POWERED))); + .booleanState(POWERED))); + public static final Block PALE_OAK_PRESSURE_PLATE = register(new Block("pale_oak_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + .booleanState(POWERED))); public static final Block MANGROVE_PRESSURE_PLATE = register(new Block("mangrove_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .booleanState(POWERED))); + .booleanState(POWERED))); public static final Block BAMBOO_PRESSURE_PLATE = register(new Block("bamboo_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .booleanState(POWERED))); + .booleanState(POWERED))); public static final Block REDSTONE_ORE = register(new Block("redstone_ore", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .booleanState(LIT))); + .booleanState(LIT))); public static final Block DEEPSLATE_REDSTONE_ORE = register(new Block("deepslate_redstone_ore", builder().requiresCorrectToolForDrops().destroyTime(4.5f) - .booleanState(LIT))); + .booleanState(LIT))); public static final Block REDSTONE_TORCH = register(new Block("redstone_torch", builder().pushReaction(PistonBehavior.DESTROY) - .booleanState(LIT))); + .booleanState(LIT))); public static final Block REDSTONE_WALL_TORCH = register(new Block("redstone_wall_torch", builder().pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(LIT))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(LIT))); public static final Block STONE_BUTTON = register(new Block("stone_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .enumState(ATTACH_FACE) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(POWERED))); + .enumState(ATTACH_FACE) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); public static final Block SNOW = register(new Block("snow", builder().requiresCorrectToolForDrops().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) - .intState(LAYERS))); + .intState(LAYERS))); public static final Block ICE = register(new Block("ice", builder().destroyTime(0.5f))); public static final Block SNOW_BLOCK = register(new Block("snow_block", builder().requiresCorrectToolForDrops().destroyTime(0.2f))); public static final Block CACTUS = register(new Block("cactus", builder().destroyTime(0.4f).pushReaction(PistonBehavior.DESTROY) - .intState(AGE_15))); + .intState(AGE_15))); public static final Block CLAY = register(new Block("clay", builder().destroyTime(0.6f))); public static final Block SUGAR_CANE = register(new Block("sugar_cane", builder().pushReaction(PistonBehavior.DESTROY) - .intState(AGE_15))); + .intState(AGE_15))); public static final Block JUKEBOX = register(new Block("jukebox", builder().setBlockEntity(BlockEntityType.JUKEBOX).destroyTime(2.0f) - .booleanState(HAS_RECORD))); + .booleanState(HAS_RECORD))); public static final Block OAK_FENCE = register(new Block("oak_fence", builder().destroyTime(2.0f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block NETHERRACK = register(new Block("netherrack", builder().requiresCorrectToolForDrops().destroyTime(0.4f))); public static final Block SOUL_SAND = register(new Block("soul_sand", builder().destroyTime(0.5f))); public static final Block SOUL_SOIL = register(new Block("soul_soil", builder().destroyTime(0.5f))); public static final Block BASALT = register(new Block("basalt", builder().requiresCorrectToolForDrops().destroyTime(1.25f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block POLISHED_BASALT = register(new Block("polished_basalt", builder().requiresCorrectToolForDrops().destroyTime(1.25f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block SOUL_TORCH = register(new Block("soul_torch", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block SOUL_WALL_TORCH = register(new Block("soul_wall_torch", builder().pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block GLOWSTONE = register(new Block("glowstone", builder().destroyTime(0.3f))); public static final Block NETHER_PORTAL = register(new Block("nether_portal", builder().destroyTime(-1.0f).pushReaction(PistonBehavior.BLOCK) - .enumState(HORIZONTAL_AXIS, Axis.X, Axis.Z))); + .enumState(HORIZONTAL_AXIS, Axis.X, Axis.Z))); public static final Block CARVED_PUMPKIN = register(new Block("carved_pumpkin", builder().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block JACK_O_LANTERN = register(new Block("jack_o_lantern", builder().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block CAKE = register(new Block("cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .intState(BITES))); + .intState(BITES))); public static final Block REPEATER = register(new Block("repeater", builder().pushReaction(PistonBehavior.DESTROY) - .intState(DELAY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(LOCKED) - .booleanState(POWERED))); + .intState(DELAY) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(LOCKED) + .booleanState(POWERED))); public static final Block WHITE_STAINED_GLASS = register(new Block("white_stained_glass", builder().destroyTime(0.3f))); public static final Block ORANGE_STAINED_GLASS = register(new Block("orange_stained_glass", builder().destroyTime(0.3f))); public static final Block MAGENTA_STAINED_GLASS = register(new Block("magenta_stained_glass", builder().destroyTime(0.3f))); @@ -658,59 +691,65 @@ public final class Blocks { public static final Block RED_STAINED_GLASS = register(new Block("red_stained_glass", builder().destroyTime(0.3f))); public static final Block BLACK_STAINED_GLASS = register(new Block("black_stained_glass", builder().destroyTime(0.3f))); public static final Block OAK_TRAPDOOR = register(new TrapDoorBlock("oak_trapdoor", builder().destroyTime(3.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .booleanState(OPEN) - .booleanState(POWERED) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); public static final Block SPRUCE_TRAPDOOR = register(new TrapDoorBlock("spruce_trapdoor", builder().destroyTime(3.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .booleanState(OPEN) - .booleanState(POWERED) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); public static final Block BIRCH_TRAPDOOR = register(new TrapDoorBlock("birch_trapdoor", builder().destroyTime(3.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .booleanState(OPEN) - .booleanState(POWERED) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); public static final Block JUNGLE_TRAPDOOR = register(new TrapDoorBlock("jungle_trapdoor", builder().destroyTime(3.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .booleanState(OPEN) - .booleanState(POWERED) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); public static final Block ACACIA_TRAPDOOR = register(new TrapDoorBlock("acacia_trapdoor", builder().destroyTime(3.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .booleanState(OPEN) - .booleanState(POWERED) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); public static final Block CHERRY_TRAPDOOR = register(new TrapDoorBlock("cherry_trapdoor", builder().destroyTime(3.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .booleanState(OPEN) - .booleanState(POWERED) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); public static final Block DARK_OAK_TRAPDOOR = register(new TrapDoorBlock("dark_oak_trapdoor", builder().destroyTime(3.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .booleanState(OPEN) - .booleanState(POWERED) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); + public static final Block PALE_OAK_TRAPDOOR = register(new TrapDoorBlock("pale_oak_trapdoor", builder().destroyTime(3.0f) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); public static final Block MANGROVE_TRAPDOOR = register(new TrapDoorBlock("mangrove_trapdoor", builder().destroyTime(3.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .booleanState(OPEN) - .booleanState(POWERED) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); public static final Block BAMBOO_TRAPDOOR = register(new TrapDoorBlock("bamboo_trapdoor", builder().destroyTime(3.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .booleanState(OPEN) - .booleanState(POWERED) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); public static final Block STONE_BRICKS = register(new Block("stone_bricks", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); public static final Block MOSSY_STONE_BRICKS = register(new Block("mossy_stone_bricks", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); public static final Block CRACKED_STONE_BRICKS = register(new Block("cracked_stone_bricks", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); @@ -724,180 +763,180 @@ public final class Blocks { public static final Block INFESTED_CRACKED_STONE_BRICKS = register(new Block("infested_cracked_stone_bricks", builder().destroyTime(0.75f))); public static final Block INFESTED_CHISELED_STONE_BRICKS = register(new Block("infested_chiseled_stone_bricks", builder().destroyTime(0.75f))); public static final Block BROWN_MUSHROOM_BLOCK = register(new Block("brown_mushroom_block", builder().destroyTime(0.2f) - .booleanState(DOWN) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(UP) - .booleanState(WEST))); + .booleanState(DOWN) + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(UP) + .booleanState(WEST))); public static final Block RED_MUSHROOM_BLOCK = register(new Block("red_mushroom_block", builder().destroyTime(0.2f) - .booleanState(DOWN) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(UP) - .booleanState(WEST))); + .booleanState(DOWN) + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(UP) + .booleanState(WEST))); public static final Block MUSHROOM_STEM = register(new Block("mushroom_stem", builder().destroyTime(0.2f) - .booleanState(DOWN) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(UP) - .booleanState(WEST))); + .booleanState(DOWN) + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(UP) + .booleanState(WEST))); public static final Block IRON_BARS = register(new Block("iron_bars", builder().requiresCorrectToolForDrops().destroyTime(5.0f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block CHAIN = register(new Block("chain", builder().requiresCorrectToolForDrops().destroyTime(5.0f) - .enumState(AXIS, Axis.VALUES) - .booleanState(WATERLOGGED))); + .enumState(AXIS, Axis.VALUES) + .booleanState(WATERLOGGED))); public static final Block GLASS_PANE = register(new Block("glass_pane", builder().destroyTime(0.3f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block PUMPKIN = register(new Block("pumpkin", builder().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY))); public static final Block MELON = register(new Block("melon", builder().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY))); public static final Block ATTACHED_PUMPKIN_STEM = register(new Block("attached_pumpkin_stem", builder().pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.PUMPKIN_SEEDS) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block ATTACHED_MELON_STEM = register(new Block("attached_melon_stem", builder().pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.MELON_SEEDS) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block PUMPKIN_STEM = register(new Block("pumpkin_stem", builder().pushReaction(PistonBehavior.DESTROY) - .intState(AGE_7))); + .intState(AGE_7))); public static final Block MELON_STEM = register(new Block("melon_stem", builder().pushReaction(PistonBehavior.DESTROY) - .intState(AGE_7))); + .intState(AGE_7))); public static final Block VINE = register(new Block("vine", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(UP) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(UP) + .booleanState(WEST))); public static final Block GLOW_LICHEN = register(new Block("glow_lichen", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .booleanState(DOWN) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(UP) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(DOWN) + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(UP) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block OAK_FENCE_GATE = register(new Block("oak_fence_gate", builder().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(IN_WALL) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(IN_WALL) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block BRICK_STAIRS = register(new Block("brick_stairs", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block STONE_BRICK_STAIRS = register(new Block("stone_brick_stairs", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block MUD_BRICK_STAIRS = register(new Block("mud_brick_stairs", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block MYCELIUM = register(new Block("mycelium", builder().destroyTime(0.6f) - .booleanState(SNOWY))); + .booleanState(SNOWY))); public static final Block LILY_PAD = register(new Block("lily_pad", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block NETHER_BRICKS = register(new Block("nether_bricks", builder().requiresCorrectToolForDrops().destroyTime(2.0f))); public static final Block NETHER_BRICK_FENCE = register(new Block("nether_brick_fence", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block NETHER_BRICK_STAIRS = register(new Block("nether_brick_stairs", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block NETHER_WART = register(new Block("nether_wart", builder().pushReaction(PistonBehavior.DESTROY) - .intState(AGE_3))); + .intState(AGE_3))); public static final Block ENCHANTING_TABLE = register(new Block("enchanting_table", builder().setBlockEntity(BlockEntityType.ENCHANTING_TABLE).requiresCorrectToolForDrops().destroyTime(5.0f))); public static final Block BREWING_STAND = register(new Block("brewing_stand", builder().setBlockEntity(BlockEntityType.BREWING_STAND).requiresCorrectToolForDrops().destroyTime(0.5f) - .booleanState(HAS_BOTTLE_0) - .booleanState(HAS_BOTTLE_1) - .booleanState(HAS_BOTTLE_2))); + .booleanState(HAS_BOTTLE_0) + .booleanState(HAS_BOTTLE_1) + .booleanState(HAS_BOTTLE_2))); public static final Block CAULDRON = register(new CauldronBlock("cauldron", builder().requiresCorrectToolForDrops().destroyTime(2.0f))); public static final Block WATER_CAULDRON = register(new CauldronBlock("water_cauldron", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .intState(LEVEL_CAULDRON))); + .intState(LEVEL_CAULDRON))); public static final Block LAVA_CAULDRON = register(new CauldronBlock("lava_cauldron", builder().requiresCorrectToolForDrops().destroyTime(2.0f))); public static final Block POWDER_SNOW_CAULDRON = register(new CauldronBlock("powder_snow_cauldron", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .intState(LEVEL_CAULDRON))); + .intState(LEVEL_CAULDRON))); public static final Block END_PORTAL = register(new Block("end_portal", builder().setBlockEntity(BlockEntityType.END_PORTAL).destroyTime(-1.0f).pushReaction(PistonBehavior.BLOCK))); public static final Block END_PORTAL_FRAME = register(new Block("end_portal_frame", builder().destroyTime(-1.0f) - .booleanState(EYE) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .booleanState(EYE) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block END_STONE = register(new Block("end_stone", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); public static final Block DRAGON_EGG = register(new Block("dragon_egg", builder().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY))); public static final Block REDSTONE_LAMP = register(new Block("redstone_lamp", builder().destroyTime(0.3f) - .booleanState(LIT))); + .booleanState(LIT))); public static final Block COCOA = register(new Block("cocoa", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .intState(AGE_2) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .intState(AGE_2) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block SANDSTONE_STAIRS = register(new Block("sandstone_stairs", builder().requiresCorrectToolForDrops().destroyTime(0.8f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block EMERALD_ORE = register(new Block("emerald_ore", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); public static final Block DEEPSLATE_EMERALD_ORE = register(new Block("deepslate_emerald_ore", builder().requiresCorrectToolForDrops().destroyTime(4.5f))); public static final Block ENDER_CHEST = register(new Block("ender_chest", builder().setBlockEntity(BlockEntityType.ENDER_CHEST).requiresCorrectToolForDrops().destroyTime(22.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block TRIPWIRE_HOOK = register(new Block("tripwire_hook", builder().pushReaction(PistonBehavior.DESTROY) - .booleanState(ATTACHED) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(POWERED))); + .booleanState(ATTACHED) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); public static final Block TRIPWIRE = register(new Block("tripwire", builder().pushReaction(PistonBehavior.DESTROY) - .booleanState(ATTACHED) - .booleanState(DISARMED) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(POWERED) - .booleanState(SOUTH) - .booleanState(WEST))); + .booleanState(ATTACHED) + .booleanState(DISARMED) + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(POWERED) + .booleanState(SOUTH) + .booleanState(WEST))); public static final Block EMERALD_BLOCK = register(new Block("emerald_block", builder().requiresCorrectToolForDrops().destroyTime(5.0f))); public static final Block SPRUCE_STAIRS = register(new Block("spruce_stairs", builder().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block BIRCH_STAIRS = register(new Block("birch_stairs", builder().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block JUNGLE_STAIRS = register(new Block("jungle_stairs", builder().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block COMMAND_BLOCK = register(new Block("command_block", builder().setBlockEntity(BlockEntityType.COMMAND_BLOCK).requiresCorrectToolForDrops().destroyTime(-1.0f) - .booleanState(CONDITIONAL) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); + .booleanState(CONDITIONAL) + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); public static final Block BEACON = register(new Block("beacon", builder().setBlockEntity(BlockEntityType.BEACON).destroyTime(3.0f))); public static final Block COBBLESTONE_WALL = register(new Block("cobblestone_wall", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(EAST_WALL) - .enumState(NORTH_WALL) - .enumState(SOUTH_WALL) - .booleanState(UP) - .booleanState(WATERLOGGED) - .enumState(WEST_WALL))); + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL))); public static final Block MOSSY_COBBLESTONE_WALL = register(new Block("mossy_cobblestone_wall", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(EAST_WALL) - .enumState(NORTH_WALL) - .enumState(SOUTH_WALL) - .booleanState(UP) - .booleanState(WATERLOGGED) - .enumState(WEST_WALL))); + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL))); public static final Block FLOWER_POT = register(new FlowerPotBlock("flower_pot", AIR, builder().pushReaction(PistonBehavior.DESTROY))); public static final Block POTTED_TORCHFLOWER = register(new FlowerPotBlock("potted_torchflower", TORCHFLOWER, builder().pushReaction(PistonBehavior.DESTROY))); public static final Block POTTED_OAK_SAPLING = register(new FlowerPotBlock("potted_oak_sapling", OAK_SAPLING, builder().pushReaction(PistonBehavior.DESTROY))); @@ -907,6 +946,7 @@ public final class Blocks { public static final Block POTTED_ACACIA_SAPLING = register(new FlowerPotBlock("potted_acacia_sapling", ACACIA_SAPLING, builder().pushReaction(PistonBehavior.DESTROY))); public static final Block POTTED_CHERRY_SAPLING = register(new FlowerPotBlock("potted_cherry_sapling", CHERRY_SAPLING, builder().pushReaction(PistonBehavior.DESTROY))); public static final Block POTTED_DARK_OAK_SAPLING = register(new FlowerPotBlock("potted_dark_oak_sapling", DARK_OAK_SAPLING, builder().pushReaction(PistonBehavior.DESTROY))); + public static final Block POTTED_PALE_OAK_SAPLING = register(new FlowerPotBlock("potted_pale_oak_sapling", PALE_OAK_SAPLING, builder().pushReaction(PistonBehavior.DESTROY))); public static final Block POTTED_MANGROVE_PROPAGULE = register(new FlowerPotBlock("potted_mangrove_propagule", MANGROVE_PROPAGULE, builder().pushReaction(PistonBehavior.DESTROY))); public static final Block POTTED_FERN = register(new FlowerPotBlock("potted_fern", FERN, builder().pushReaction(PistonBehavior.DESTROY))); public static final Block POTTED_DANDELION = register(new FlowerPotBlock("potted_dandelion", DANDELION, builder().pushReaction(PistonBehavior.DESTROY))); @@ -927,129 +967,133 @@ public final class Blocks { public static final Block POTTED_DEAD_BUSH = register(new FlowerPotBlock("potted_dead_bush", DEAD_BUSH, builder().pushReaction(PistonBehavior.DESTROY))); public static final Block POTTED_CACTUS = register(new FlowerPotBlock("potted_cactus", CACTUS, builder().pushReaction(PistonBehavior.DESTROY))); public static final Block CARROTS = register(new Block("carrots", builder().pushReaction(PistonBehavior.DESTROY) - .intState(AGE_7))); + .intState(AGE_7))); public static final Block POTATOES = register(new Block("potatoes", builder().pushReaction(PistonBehavior.DESTROY) - .intState(AGE_7))); + .intState(AGE_7))); public static final Block OAK_BUTTON = register(new Block("oak_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .enumState(ATTACH_FACE) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(POWERED))); + .enumState(ATTACH_FACE) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); public static final Block SPRUCE_BUTTON = register(new Block("spruce_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .enumState(ATTACH_FACE) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(POWERED))); + .enumState(ATTACH_FACE) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); public static final Block BIRCH_BUTTON = register(new Block("birch_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .enumState(ATTACH_FACE) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(POWERED))); + .enumState(ATTACH_FACE) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); public static final Block JUNGLE_BUTTON = register(new Block("jungle_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .enumState(ATTACH_FACE) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(POWERED))); + .enumState(ATTACH_FACE) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); public static final Block ACACIA_BUTTON = register(new Block("acacia_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .enumState(ATTACH_FACE) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(POWERED))); + .enumState(ATTACH_FACE) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); public static final Block CHERRY_BUTTON = register(new Block("cherry_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .enumState(ATTACH_FACE) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(POWERED))); + .enumState(ATTACH_FACE) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); public static final Block DARK_OAK_BUTTON = register(new Block("dark_oak_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .enumState(ATTACH_FACE) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(POWERED))); + .enumState(ATTACH_FACE) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); + public static final Block PALE_OAK_BUTTON = register(new Block("pale_oak_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) + .enumState(ATTACH_FACE) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); public static final Block MANGROVE_BUTTON = register(new Block("mangrove_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .enumState(ATTACH_FACE) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(POWERED))); + .enumState(ATTACH_FACE) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); public static final Block BAMBOO_BUTTON = register(new Block("bamboo_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .enumState(ATTACH_FACE) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(POWERED))); + .enumState(ATTACH_FACE) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); public static final Block SKELETON_SKULL = register(new SkullBlock("skeleton_skull", SkullBlock.Type.SKELETON, builder().setBlockEntity(BlockEntityType.SKULL).destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) - .booleanState(POWERED) - .intState(ROTATION_16))); + .booleanState(POWERED) + .intState(ROTATION_16))); public static final Block SKELETON_WALL_SKULL = register(new WallSkullBlock("skeleton_wall_skull", SkullBlock.Type.SKELETON, builder().setBlockEntity(BlockEntityType.SKULL).destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); public static final Block WITHER_SKELETON_SKULL = register(new SkullBlock("wither_skeleton_skull", SkullBlock.Type.WITHER_SKELETON, builder().setBlockEntity(BlockEntityType.SKULL).destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) - .booleanState(POWERED) - .intState(ROTATION_16))); + .booleanState(POWERED) + .intState(ROTATION_16))); public static final Block WITHER_SKELETON_WALL_SKULL = register(new WallSkullBlock("wither_skeleton_wall_skull", SkullBlock.Type.WITHER_SKELETON, builder().setBlockEntity(BlockEntityType.SKULL).destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); public static final Block ZOMBIE_HEAD = register(new SkullBlock("zombie_head", SkullBlock.Type.ZOMBIE, builder().setBlockEntity(BlockEntityType.SKULL).destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) - .booleanState(POWERED) - .intState(ROTATION_16))); + .booleanState(POWERED) + .intState(ROTATION_16))); public static final Block ZOMBIE_WALL_HEAD = register(new WallSkullBlock("zombie_wall_head", SkullBlock.Type.ZOMBIE, builder().setBlockEntity(BlockEntityType.SKULL).destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); public static final Block PLAYER_HEAD = register(new SkullBlock("player_head", SkullBlock.Type.PLAYER, builder().setBlockEntity(BlockEntityType.SKULL).destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) - .booleanState(POWERED) - .intState(ROTATION_16))); + .booleanState(POWERED) + .intState(ROTATION_16))); public static final Block PLAYER_WALL_HEAD = register(new WallSkullBlock("player_wall_head", SkullBlock.Type.PLAYER, builder().setBlockEntity(BlockEntityType.SKULL).destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); public static final Block CREEPER_HEAD = register(new SkullBlock("creeper_head", SkullBlock.Type.CREEPER, builder().setBlockEntity(BlockEntityType.SKULL).destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) - .booleanState(POWERED) - .intState(ROTATION_16))); + .booleanState(POWERED) + .intState(ROTATION_16))); public static final Block CREEPER_WALL_HEAD = register(new WallSkullBlock("creeper_wall_head", SkullBlock.Type.CREEPER, builder().setBlockEntity(BlockEntityType.SKULL).destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); public static final Block DRAGON_HEAD = register(new SkullBlock("dragon_head", SkullBlock.Type.DRAGON, builder().setBlockEntity(BlockEntityType.SKULL).destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) - .booleanState(POWERED) - .intState(ROTATION_16))); + .booleanState(POWERED) + .intState(ROTATION_16))); public static final Block DRAGON_WALL_HEAD = register(new WallSkullBlock("dragon_wall_head", SkullBlock.Type.DRAGON, builder().setBlockEntity(BlockEntityType.SKULL).destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); public static final Block PIGLIN_HEAD = register(new SkullBlock("piglin_head", SkullBlock.Type.PIGLIN, builder().setBlockEntity(BlockEntityType.SKULL).destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) - .booleanState(POWERED) - .intState(ROTATION_16))); + .booleanState(POWERED) + .intState(ROTATION_16))); public static final Block PIGLIN_WALL_HEAD = register(new WallSkullBlock("piglin_wall_head", SkullBlock.Type.PIGLIN, builder().setBlockEntity(BlockEntityType.SKULL).destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); public static final Block ANVIL = register(new Block("anvil", builder().requiresCorrectToolForDrops().destroyTime(5.0f).pushReaction(PistonBehavior.BLOCK) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block CHIPPED_ANVIL = register(new Block("chipped_anvil", builder().requiresCorrectToolForDrops().destroyTime(5.0f).pushReaction(PistonBehavior.BLOCK) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block DAMAGED_ANVIL = register(new Block("damaged_anvil", builder().requiresCorrectToolForDrops().destroyTime(5.0f).pushReaction(PistonBehavior.BLOCK) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block TRAPPED_CHEST = register(new ChestBlock("trapped_chest", builder().setBlockEntity(BlockEntityType.TRAPPED_CHEST).destroyTime(2.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(CHEST_TYPE, ChestType.VALUES) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(CHEST_TYPE, ChestType.VALUES) + .booleanState(WATERLOGGED))); public static final Block LIGHT_WEIGHTED_PRESSURE_PLATE = register(new Block("light_weighted_pressure_plate", builder().requiresCorrectToolForDrops().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .intState(POWER))); + .intState(POWER))); public static final Block HEAVY_WEIGHTED_PRESSURE_PLATE = register(new Block("heavy_weighted_pressure_plate", builder().requiresCorrectToolForDrops().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .intState(POWER))); + .intState(POWER))); public static final Block COMPARATOR = register(new Block("comparator", builder().setBlockEntity(BlockEntityType.COMPARATOR).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(MODE_COMPARATOR) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(MODE_COMPARATOR) + .booleanState(POWERED))); public static final Block DAYLIGHT_DETECTOR = register(new Block("daylight_detector", builder().setBlockEntity(BlockEntityType.DAYLIGHT_DETECTOR).destroyTime(0.2f) - .booleanState(INVERTED) - .intState(POWER))); + .booleanState(INVERTED) + .intState(POWER))); public static final Block REDSTONE_BLOCK = register(new Block("redstone_block", builder().requiresCorrectToolForDrops().destroyTime(5.0f))); public static final Block NETHER_QUARTZ_ORE = register(new Block("nether_quartz_ore", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); public static final Block HOPPER = register(new Block("hopper", builder().setBlockEntity(BlockEntityType.HOPPER).requiresCorrectToolForDrops().destroyTime(3.0f) - .booleanState(ENABLED) - .enumState(FACING_HOPPER, Direction.DOWN, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .booleanState(ENABLED) + .enumState(FACING_HOPPER, Direction.DOWN, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block QUARTZ_BLOCK = register(new Block("quartz_block", builder().requiresCorrectToolForDrops().destroyTime(0.8f))); public static final Block CHISELED_QUARTZ_BLOCK = register(new Block("chiseled_quartz_block", builder().requiresCorrectToolForDrops().destroyTime(0.8f))); public static final Block QUARTZ_PILLAR = register(new Block("quartz_pillar", builder().requiresCorrectToolForDrops().destroyTime(0.8f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block QUARTZ_STAIRS = register(new Block("quartz_stairs", builder().requiresCorrectToolForDrops().destroyTime(0.8f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block ACTIVATOR_RAIL = register(new Block("activator_rail", builder().destroyTime(0.7f) - .booleanState(POWERED) - .enumState(RAIL_SHAPE_STRAIGHT) - .booleanState(WATERLOGGED))); + .booleanState(POWERED) + .enumState(RAIL_SHAPE_STRAIGHT) + .booleanState(WATERLOGGED))); public static final Block DROPPER = register(new Block("dropper", builder().setBlockEntity(BlockEntityType.DROPPER).requiresCorrectToolForDrops().destroyTime(3.5f) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) - .booleanState(TRIGGERED))); + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) + .booleanState(TRIGGERED))); public static final Block WHITE_TERRACOTTA = register(new Block("white_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.25f))); public static final Block ORANGE_TERRACOTTA = register(new Block("orange_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.25f))); public static final Block MAGENTA_TERRACOTTA = register(new Block("magenta_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.25f))); @@ -1067,173 +1111,178 @@ public final class Blocks { public static final Block RED_TERRACOTTA = register(new Block("red_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.25f))); public static final Block BLACK_TERRACOTTA = register(new Block("black_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.25f))); public static final Block WHITE_STAINED_GLASS_PANE = register(new Block("white_stained_glass_pane", builder().destroyTime(0.3f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block ORANGE_STAINED_GLASS_PANE = register(new Block("orange_stained_glass_pane", builder().destroyTime(0.3f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block MAGENTA_STAINED_GLASS_PANE = register(new Block("magenta_stained_glass_pane", builder().destroyTime(0.3f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block LIGHT_BLUE_STAINED_GLASS_PANE = register(new Block("light_blue_stained_glass_pane", builder().destroyTime(0.3f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block YELLOW_STAINED_GLASS_PANE = register(new Block("yellow_stained_glass_pane", builder().destroyTime(0.3f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block LIME_STAINED_GLASS_PANE = register(new Block("lime_stained_glass_pane", builder().destroyTime(0.3f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block PINK_STAINED_GLASS_PANE = register(new Block("pink_stained_glass_pane", builder().destroyTime(0.3f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block GRAY_STAINED_GLASS_PANE = register(new Block("gray_stained_glass_pane", builder().destroyTime(0.3f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block LIGHT_GRAY_STAINED_GLASS_PANE = register(new Block("light_gray_stained_glass_pane", builder().destroyTime(0.3f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block CYAN_STAINED_GLASS_PANE = register(new Block("cyan_stained_glass_pane", builder().destroyTime(0.3f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block PURPLE_STAINED_GLASS_PANE = register(new Block("purple_stained_glass_pane", builder().destroyTime(0.3f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block BLUE_STAINED_GLASS_PANE = register(new Block("blue_stained_glass_pane", builder().destroyTime(0.3f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block BROWN_STAINED_GLASS_PANE = register(new Block("brown_stained_glass_pane", builder().destroyTime(0.3f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block GREEN_STAINED_GLASS_PANE = register(new Block("green_stained_glass_pane", builder().destroyTime(0.3f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block RED_STAINED_GLASS_PANE = register(new Block("red_stained_glass_pane", builder().destroyTime(0.3f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block BLACK_STAINED_GLASS_PANE = register(new Block("black_stained_glass_pane", builder().destroyTime(0.3f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block ACACIA_STAIRS = register(new Block("acacia_stairs", builder().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block CHERRY_STAIRS = register(new Block("cherry_stairs", builder().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block DARK_OAK_STAIRS = register(new Block("dark_oak_stairs", builder().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); + public static final Block PALE_OAK_STAIRS = register(new Block("pale_oak_stairs", builder().destroyTime(2.0f) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block MANGROVE_STAIRS = register(new Block("mangrove_stairs", builder().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block BAMBOO_STAIRS = register(new Block("bamboo_stairs", builder().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block BAMBOO_MOSAIC_STAIRS = register(new Block("bamboo_mosaic_stairs", builder().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block SLIME_BLOCK = register(new Block("slime_block", builder())); public static final Block BARRIER = register(new Block("barrier", builder().destroyTime(-1.0f).pushReaction(PistonBehavior.BLOCK) - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block LIGHT = register(new Block("light", builder().destroyTime(-1.0f) - .intState(LEVEL) - .booleanState(WATERLOGGED))); + .intState(LEVEL) + .booleanState(WATERLOGGED))); public static final Block IRON_TRAPDOOR = register(new TrapDoorBlock("iron_trapdoor", builder().requiresCorrectToolForDrops().destroyTime(5.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .booleanState(OPEN) - .booleanState(POWERED) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); public static final Block PRISMARINE = register(new Block("prismarine", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); public static final Block PRISMARINE_BRICKS = register(new Block("prismarine_bricks", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); public static final Block DARK_PRISMARINE = register(new Block("dark_prismarine", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); public static final Block PRISMARINE_STAIRS = register(new Block("prismarine_stairs", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block PRISMARINE_BRICK_STAIRS = register(new Block("prismarine_brick_stairs", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block DARK_PRISMARINE_STAIRS = register(new Block("dark_prismarine_stairs", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block PRISMARINE_SLAB = register(new Block("prismarine_slab", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block PRISMARINE_BRICK_SLAB = register(new Block("prismarine_brick_slab", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block DARK_PRISMARINE_SLAB = register(new Block("dark_prismarine_slab", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block SEA_LANTERN = register(new Block("sea_lantern", builder().destroyTime(0.3f))); public static final Block HAY_BLOCK = register(new Block("hay_block", builder().destroyTime(0.5f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block WHITE_CARPET = register(new Block("white_carpet", builder().destroyTime(0.1f))); public static final Block ORANGE_CARPET = register(new Block("orange_carpet", builder().destroyTime(0.1f))); public static final Block MAGENTA_CARPET = register(new Block("magenta_carpet", builder().destroyTime(0.1f))); @@ -1254,415 +1303,435 @@ public final class Blocks { public static final Block COAL_BLOCK = register(new Block("coal_block", builder().requiresCorrectToolForDrops().destroyTime(5.0f))); public static final Block PACKED_ICE = register(new Block("packed_ice", builder().destroyTime(0.5f))); public static final Block SUNFLOWER = register(new Block("sunflower", builder().pushReaction(PistonBehavior.DESTROY) - .enumState(DOUBLE_BLOCK_HALF))); + .enumState(DOUBLE_BLOCK_HALF))); public static final Block LILAC = register(new Block("lilac", builder().pushReaction(PistonBehavior.DESTROY) - .enumState(DOUBLE_BLOCK_HALF))); + .enumState(DOUBLE_BLOCK_HALF))); public static final Block ROSE_BUSH = register(new Block("rose_bush", builder().pushReaction(PistonBehavior.DESTROY) - .enumState(DOUBLE_BLOCK_HALF))); + .enumState(DOUBLE_BLOCK_HALF))); public static final Block PEONY = register(new Block("peony", builder().pushReaction(PistonBehavior.DESTROY) - .enumState(DOUBLE_BLOCK_HALF))); + .enumState(DOUBLE_BLOCK_HALF))); public static final Block TALL_GRASS = register(new Block("tall_grass", builder().pushReaction(PistonBehavior.DESTROY) - .enumState(DOUBLE_BLOCK_HALF))); + .enumState(DOUBLE_BLOCK_HALF))); public static final Block LARGE_FERN = register(new Block("large_fern", builder().pushReaction(PistonBehavior.DESTROY) - .enumState(DOUBLE_BLOCK_HALF))); + .enumState(DOUBLE_BLOCK_HALF))); public static final Block WHITE_BANNER = register(new BannerBlock("white_banner", 0, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .intState(ROTATION_16))); + .intState(ROTATION_16))); public static final Block ORANGE_BANNER = register(new BannerBlock("orange_banner", 1, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .intState(ROTATION_16))); + .intState(ROTATION_16))); public static final Block MAGENTA_BANNER = register(new BannerBlock("magenta_banner", 2, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .intState(ROTATION_16))); + .intState(ROTATION_16))); public static final Block LIGHT_BLUE_BANNER = register(new BannerBlock("light_blue_banner", 3, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .intState(ROTATION_16))); + .intState(ROTATION_16))); public static final Block YELLOW_BANNER = register(new BannerBlock("yellow_banner", 4, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .intState(ROTATION_16))); + .intState(ROTATION_16))); public static final Block LIME_BANNER = register(new BannerBlock("lime_banner", 5, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .intState(ROTATION_16))); + .intState(ROTATION_16))); public static final Block PINK_BANNER = register(new BannerBlock("pink_banner", 6, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .intState(ROTATION_16))); + .intState(ROTATION_16))); public static final Block GRAY_BANNER = register(new BannerBlock("gray_banner", 7, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .intState(ROTATION_16))); + .intState(ROTATION_16))); public static final Block LIGHT_GRAY_BANNER = register(new BannerBlock("light_gray_banner", 8, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .intState(ROTATION_16))); + .intState(ROTATION_16))); public static final Block CYAN_BANNER = register(new BannerBlock("cyan_banner", 9, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .intState(ROTATION_16))); + .intState(ROTATION_16))); public static final Block PURPLE_BANNER = register(new BannerBlock("purple_banner", 10, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .intState(ROTATION_16))); + .intState(ROTATION_16))); public static final Block BLUE_BANNER = register(new BannerBlock("blue_banner", 11, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .intState(ROTATION_16))); + .intState(ROTATION_16))); public static final Block BROWN_BANNER = register(new BannerBlock("brown_banner", 12, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .intState(ROTATION_16))); + .intState(ROTATION_16))); public static final Block GREEN_BANNER = register(new BannerBlock("green_banner", 13, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .intState(ROTATION_16))); + .intState(ROTATION_16))); public static final Block RED_BANNER = register(new BannerBlock("red_banner", 14, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .intState(ROTATION_16))); + .intState(ROTATION_16))); public static final Block BLACK_BANNER = register(new BannerBlock("black_banner", 15, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .intState(ROTATION_16))); + .intState(ROTATION_16))); public static final Block WHITE_WALL_BANNER = register(new BannerBlock("white_wall_banner", 0, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block ORANGE_WALL_BANNER = register(new BannerBlock("orange_wall_banner", 1, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block MAGENTA_WALL_BANNER = register(new BannerBlock("magenta_wall_banner", 2, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block LIGHT_BLUE_WALL_BANNER = register(new BannerBlock("light_blue_wall_banner", 3, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block YELLOW_WALL_BANNER = register(new BannerBlock("yellow_wall_banner", 4, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block LIME_WALL_BANNER = register(new BannerBlock("lime_wall_banner", 5, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block PINK_WALL_BANNER = register(new BannerBlock("pink_wall_banner", 6, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block GRAY_WALL_BANNER = register(new BannerBlock("gray_wall_banner", 7, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block LIGHT_GRAY_WALL_BANNER = register(new BannerBlock("light_gray_wall_banner", 8, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block CYAN_WALL_BANNER = register(new BannerBlock("cyan_wall_banner", 9, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block PURPLE_WALL_BANNER = register(new BannerBlock("purple_wall_banner", 10, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block BLUE_WALL_BANNER = register(new BannerBlock("blue_wall_banner", 11, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block BROWN_WALL_BANNER = register(new BannerBlock("brown_wall_banner", 12, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block GREEN_WALL_BANNER = register(new BannerBlock("green_wall_banner", 13, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block RED_WALL_BANNER = register(new BannerBlock("red_wall_banner", 14, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block BLACK_WALL_BANNER = register(new BannerBlock("black_wall_banner", 15, builder().setBlockEntity(BlockEntityType.BANNER).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block RED_SANDSTONE = register(new Block("red_sandstone", builder().requiresCorrectToolForDrops().destroyTime(0.8f))); public static final Block CHISELED_RED_SANDSTONE = register(new Block("chiseled_red_sandstone", builder().requiresCorrectToolForDrops().destroyTime(0.8f))); public static final Block CUT_RED_SANDSTONE = register(new Block("cut_red_sandstone", builder().requiresCorrectToolForDrops().destroyTime(0.8f))); public static final Block RED_SANDSTONE_STAIRS = register(new Block("red_sandstone_stairs", builder().requiresCorrectToolForDrops().destroyTime(0.8f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block OAK_SLAB = register(new Block("oak_slab", builder().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block SPRUCE_SLAB = register(new Block("spruce_slab", builder().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block BIRCH_SLAB = register(new Block("birch_slab", builder().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block JUNGLE_SLAB = register(new Block("jungle_slab", builder().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block ACACIA_SLAB = register(new Block("acacia_slab", builder().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block CHERRY_SLAB = register(new Block("cherry_slab", builder().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block DARK_OAK_SLAB = register(new Block("dark_oak_slab", builder().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); + public static final Block PALE_OAK_SLAB = register(new Block("pale_oak_slab", builder().destroyTime(2.0f) + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block MANGROVE_SLAB = register(new Block("mangrove_slab", builder().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block BAMBOO_SLAB = register(new Block("bamboo_slab", builder().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block BAMBOO_MOSAIC_SLAB = register(new Block("bamboo_mosaic_slab", builder().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block STONE_SLAB = register(new Block("stone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block SMOOTH_STONE_SLAB = register(new Block("smooth_stone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block SANDSTONE_SLAB = register(new Block("sandstone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block CUT_SANDSTONE_SLAB = register(new Block("cut_sandstone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block PETRIFIED_OAK_SLAB = register(new Block("petrified_oak_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block COBBLESTONE_SLAB = register(new Block("cobblestone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block BRICK_SLAB = register(new Block("brick_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block STONE_BRICK_SLAB = register(new Block("stone_brick_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block MUD_BRICK_SLAB = register(new Block("mud_brick_slab", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block NETHER_BRICK_SLAB = register(new Block("nether_brick_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block QUARTZ_SLAB = register(new Block("quartz_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block RED_SANDSTONE_SLAB = register(new Block("red_sandstone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block CUT_RED_SANDSTONE_SLAB = register(new Block("cut_red_sandstone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block PURPUR_SLAB = register(new Block("purpur_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block SMOOTH_STONE = register(new Block("smooth_stone", builder().requiresCorrectToolForDrops().destroyTime(2.0f))); public static final Block SMOOTH_SANDSTONE = register(new Block("smooth_sandstone", builder().requiresCorrectToolForDrops().destroyTime(2.0f))); public static final Block SMOOTH_QUARTZ = register(new Block("smooth_quartz", builder().requiresCorrectToolForDrops().destroyTime(2.0f))); public static final Block SMOOTH_RED_SANDSTONE = register(new Block("smooth_red_sandstone", builder().requiresCorrectToolForDrops().destroyTime(2.0f))); public static final Block SPRUCE_FENCE_GATE = register(new Block("spruce_fence_gate", builder().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(IN_WALL) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(IN_WALL) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block BIRCH_FENCE_GATE = register(new Block("birch_fence_gate", builder().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(IN_WALL) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(IN_WALL) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block JUNGLE_FENCE_GATE = register(new Block("jungle_fence_gate", builder().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(IN_WALL) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(IN_WALL) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block ACACIA_FENCE_GATE = register(new Block("acacia_fence_gate", builder().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(IN_WALL) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(IN_WALL) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block CHERRY_FENCE_GATE = register(new Block("cherry_fence_gate", builder().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(IN_WALL) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(IN_WALL) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block DARK_OAK_FENCE_GATE = register(new Block("dark_oak_fence_gate", builder().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(IN_WALL) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(IN_WALL) + .booleanState(OPEN) + .booleanState(POWERED))); + public static final Block PALE_OAK_FENCE_GATE = register(new Block("pale_oak_fence_gate", builder().destroyTime(2.0f) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(IN_WALL) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block MANGROVE_FENCE_GATE = register(new Block("mangrove_fence_gate", builder().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(IN_WALL) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(IN_WALL) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block BAMBOO_FENCE_GATE = register(new Block("bamboo_fence_gate", builder().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(IN_WALL) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(IN_WALL) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block SPRUCE_FENCE = register(new Block("spruce_fence", builder().destroyTime(2.0f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block BIRCH_FENCE = register(new Block("birch_fence", builder().destroyTime(2.0f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block JUNGLE_FENCE = register(new Block("jungle_fence", builder().destroyTime(2.0f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block ACACIA_FENCE = register(new Block("acacia_fence", builder().destroyTime(2.0f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block CHERRY_FENCE = register(new Block("cherry_fence", builder().destroyTime(2.0f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block DARK_OAK_FENCE = register(new Block("dark_oak_fence", builder().destroyTime(2.0f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); + public static final Block PALE_OAK_FENCE = register(new Block("pale_oak_fence", builder().destroyTime(2.0f) + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block MANGROVE_FENCE = register(new Block("mangrove_fence", builder().destroyTime(2.0f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block BAMBOO_FENCE = register(new Block("bamboo_fence", builder().destroyTime(2.0f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block SPRUCE_DOOR = register(new DoorBlock("spruce_door", builder().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(DOUBLE_BLOCK_HALF) - .enumState(DOOR_HINGE) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF) + .enumState(DOOR_HINGE) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block BIRCH_DOOR = register(new DoorBlock("birch_door", builder().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(DOUBLE_BLOCK_HALF) - .enumState(DOOR_HINGE) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF) + .enumState(DOOR_HINGE) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block JUNGLE_DOOR = register(new DoorBlock("jungle_door", builder().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(DOUBLE_BLOCK_HALF) - .enumState(DOOR_HINGE) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF) + .enumState(DOOR_HINGE) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block ACACIA_DOOR = register(new DoorBlock("acacia_door", builder().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(DOUBLE_BLOCK_HALF) - .enumState(DOOR_HINGE) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF) + .enumState(DOOR_HINGE) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block CHERRY_DOOR = register(new DoorBlock("cherry_door", builder().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(DOUBLE_BLOCK_HALF) - .enumState(DOOR_HINGE) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF) + .enumState(DOOR_HINGE) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block DARK_OAK_DOOR = register(new DoorBlock("dark_oak_door", builder().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(DOUBLE_BLOCK_HALF) - .enumState(DOOR_HINGE) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF) + .enumState(DOOR_HINGE) + .booleanState(OPEN) + .booleanState(POWERED))); + public static final Block PALE_OAK_DOOR = register(new DoorBlock("pale_oak_door", builder().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF) + .enumState(DOOR_HINGE) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block MANGROVE_DOOR = register(new DoorBlock("mangrove_door", builder().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(DOUBLE_BLOCK_HALF) - .enumState(DOOR_HINGE) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF) + .enumState(DOOR_HINGE) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block BAMBOO_DOOR = register(new DoorBlock("bamboo_door", builder().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(DOUBLE_BLOCK_HALF) - .enumState(DOOR_HINGE) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF) + .enumState(DOOR_HINGE) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block END_ROD = register(new Block("end_rod", builder() - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); public static final Block CHORUS_PLANT = register(new Block("chorus_plant", builder().destroyTime(0.4f).pushReaction(PistonBehavior.DESTROY) - .booleanState(DOWN) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(UP) - .booleanState(WEST))); + .booleanState(DOWN) + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(UP) + .booleanState(WEST))); public static final Block CHORUS_FLOWER = register(new Block("chorus_flower", builder().destroyTime(0.4f).pushReaction(PistonBehavior.DESTROY) - .intState(AGE_5))); + .intState(AGE_5))); public static final Block PURPUR_BLOCK = register(new Block("purpur_block", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); public static final Block PURPUR_PILLAR = register(new Block("purpur_pillar", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block PURPUR_STAIRS = register(new Block("purpur_stairs", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block END_STONE_BRICKS = register(new Block("end_stone_bricks", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); public static final Block TORCHFLOWER_CROP = register(new Block("torchflower_crop", builder().pushReaction(PistonBehavior.DESTROY) - .intState(AGE_1))); + .intState(AGE_1))); public static final Block PITCHER_CROP = register(new Block("pitcher_crop", builder().pushReaction(PistonBehavior.DESTROY) - .intState(AGE_4) - .enumState(DOUBLE_BLOCK_HALF))); + .intState(AGE_4) + .enumState(DOUBLE_BLOCK_HALF))); public static final Block PITCHER_PLANT = register(new Block("pitcher_plant", builder().pushReaction(PistonBehavior.DESTROY) - .enumState(DOUBLE_BLOCK_HALF))); + .enumState(DOUBLE_BLOCK_HALF))); public static final Block BEETROOTS = register(new Block("beetroots", builder().pushReaction(PistonBehavior.DESTROY) - .intState(AGE_3))); + .intState(AGE_3))); public static final Block DIRT_PATH = register(new Block("dirt_path", builder().destroyTime(0.65f))); public static final Block END_GATEWAY = register(new Block("end_gateway", builder().setBlockEntity(BlockEntityType.END_GATEWAY).destroyTime(-1.0f).pushReaction(PistonBehavior.BLOCK))); public static final Block REPEATING_COMMAND_BLOCK = register(new Block("repeating_command_block", builder().setBlockEntity(BlockEntityType.COMMAND_BLOCK).requiresCorrectToolForDrops().destroyTime(-1.0f) - .booleanState(CONDITIONAL) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); + .booleanState(CONDITIONAL) + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); public static final Block CHAIN_COMMAND_BLOCK = register(new Block("chain_command_block", builder().setBlockEntity(BlockEntityType.COMMAND_BLOCK).requiresCorrectToolForDrops().destroyTime(-1.0f) - .booleanState(CONDITIONAL) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); + .booleanState(CONDITIONAL) + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); public static final Block FROSTED_ICE = register(new Block("frosted_ice", builder().destroyTime(0.5f) - .intState(AGE_3))); + .intState(AGE_3))); public static final Block MAGMA_BLOCK = register(new Block("magma_block", builder().requiresCorrectToolForDrops().destroyTime(0.5f))); public static final Block NETHER_WART_BLOCK = register(new Block("nether_wart_block", builder().destroyTime(1.0f))); public static final Block RED_NETHER_BRICKS = register(new Block("red_nether_bricks", builder().requiresCorrectToolForDrops().destroyTime(2.0f))); public static final Block BONE_BLOCK = register(new Block("bone_block", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block STRUCTURE_VOID = register(new Block("structure_void", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block OBSERVER = register(new Block("observer", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) - .booleanState(POWERED))); + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) + .booleanState(POWERED))); public static final Block SHULKER_BOX = register(new Block("shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); public static final Block WHITE_SHULKER_BOX = register(new Block("white_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); public static final Block ORANGE_SHULKER_BOX = register(new Block("orange_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); public static final Block MAGENTA_SHULKER_BOX = register(new Block("magenta_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); public static final Block LIGHT_BLUE_SHULKER_BOX = register(new Block("light_blue_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); public static final Block YELLOW_SHULKER_BOX = register(new Block("yellow_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); public static final Block LIME_SHULKER_BOX = register(new Block("lime_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); public static final Block PINK_SHULKER_BOX = register(new Block("pink_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); public static final Block GRAY_SHULKER_BOX = register(new Block("gray_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); public static final Block LIGHT_GRAY_SHULKER_BOX = register(new Block("light_gray_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); public static final Block CYAN_SHULKER_BOX = register(new Block("cyan_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); public static final Block PURPLE_SHULKER_BOX = register(new Block("purple_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); public static final Block BLUE_SHULKER_BOX = register(new Block("blue_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); public static final Block BROWN_SHULKER_BOX = register(new Block("brown_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); public static final Block GREEN_SHULKER_BOX = register(new Block("green_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); public static final Block RED_SHULKER_BOX = register(new Block("red_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); public static final Block BLACK_SHULKER_BOX = register(new Block("black_shulker_box", builder().setBlockEntity(BlockEntityType.SHULKER_BOX).destroyTime(2.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN))); public static final Block WHITE_GLAZED_TERRACOTTA = register(new Block("white_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block ORANGE_GLAZED_TERRACOTTA = register(new Block("orange_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block MAGENTA_GLAZED_TERRACOTTA = register(new Block("magenta_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block LIGHT_BLUE_GLAZED_TERRACOTTA = register(new Block("light_blue_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block YELLOW_GLAZED_TERRACOTTA = register(new Block("yellow_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block LIME_GLAZED_TERRACOTTA = register(new Block("lime_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block PINK_GLAZED_TERRACOTTA = register(new Block("pink_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block GRAY_GLAZED_TERRACOTTA = register(new Block("gray_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block LIGHT_GRAY_GLAZED_TERRACOTTA = register(new Block("light_gray_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block CYAN_GLAZED_TERRACOTTA = register(new Block("cyan_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block PURPLE_GLAZED_TERRACOTTA = register(new Block("purple_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block BLUE_GLAZED_TERRACOTTA = register(new Block("blue_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block BROWN_GLAZED_TERRACOTTA = register(new Block("brown_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block GREEN_GLAZED_TERRACOTTA = register(new Block("green_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block RED_GLAZED_TERRACOTTA = register(new Block("red_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block BLACK_GLAZED_TERRACOTTA = register(new Block("black_glazed_terracotta", builder().requiresCorrectToolForDrops().destroyTime(1.4f).pushReaction(PistonBehavior.PUSH_ONLY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block WHITE_CONCRETE = register(new Block("white_concrete", builder().requiresCorrectToolForDrops().destroyTime(1.8f))); public static final Block ORANGE_CONCRETE = register(new Block("orange_concrete", builder().requiresCorrectToolForDrops().destroyTime(1.8f))); public static final Block MAGENTA_CONCRETE = register(new Block("magenta_concrete", builder().requiresCorrectToolForDrops().destroyTime(1.8f))); @@ -1696,14 +1765,14 @@ public final class Blocks { public static final Block RED_CONCRETE_POWDER = register(new Block("red_concrete_powder", builder().destroyTime(0.5f))); public static final Block BLACK_CONCRETE_POWDER = register(new Block("black_concrete_powder", builder().destroyTime(0.5f))); public static final Block KELP = register(new Block("kelp", builder().pushReaction(PistonBehavior.DESTROY) - .intState(AGE_25))); + .intState(AGE_25))); public static final Block KELP_PLANT = register(new Block("kelp_plant", builder().pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.KELP))); public static final Block DRIED_KELP_BLOCK = register(new Block("dried_kelp_block", builder().destroyTime(0.5f))); public static final Block TURTLE_EGG = register(new Block("turtle_egg", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .intState(EGGS) - .intState(HATCH))); + .intState(EGGS) + .intState(HATCH))); public static final Block SNIFFER_EGG = register(new Block("sniffer_egg", builder().destroyTime(0.5f) - .intState(HATCH))); + .intState(HATCH))); public static final Block DEAD_TUBE_CORAL_BLOCK = register(new Block("dead_tube_coral_block", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); public static final Block DEAD_BRAIN_CORAL_BLOCK = register(new Block("dead_brain_coral_block", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); public static final Block DEAD_BUBBLE_CORAL_BLOCK = register(new Block("dead_bubble_coral_block", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); @@ -1715,480 +1784,480 @@ public final class Blocks { public static final Block FIRE_CORAL_BLOCK = register(new Block("fire_coral_block", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); public static final Block HORN_CORAL_BLOCK = register(new Block("horn_coral_block", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); public static final Block DEAD_TUBE_CORAL = register(new Block("dead_tube_coral", builder().requiresCorrectToolForDrops() - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block DEAD_BRAIN_CORAL = register(new Block("dead_brain_coral", builder().requiresCorrectToolForDrops() - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block DEAD_BUBBLE_CORAL = register(new Block("dead_bubble_coral", builder().requiresCorrectToolForDrops() - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block DEAD_FIRE_CORAL = register(new Block("dead_fire_coral", builder().requiresCorrectToolForDrops() - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block DEAD_HORN_CORAL = register(new Block("dead_horn_coral", builder().requiresCorrectToolForDrops() - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block TUBE_CORAL = register(new Block("tube_coral", builder().pushReaction(PistonBehavior.DESTROY) - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block BRAIN_CORAL = register(new Block("brain_coral", builder().pushReaction(PistonBehavior.DESTROY) - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block BUBBLE_CORAL = register(new Block("bubble_coral", builder().pushReaction(PistonBehavior.DESTROY) - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block FIRE_CORAL = register(new Block("fire_coral", builder().pushReaction(PistonBehavior.DESTROY) - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block HORN_CORAL = register(new Block("horn_coral", builder().pushReaction(PistonBehavior.DESTROY) - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block DEAD_TUBE_CORAL_FAN = register(new Block("dead_tube_coral_fan", builder().requiresCorrectToolForDrops() - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block DEAD_BRAIN_CORAL_FAN = register(new Block("dead_brain_coral_fan", builder().requiresCorrectToolForDrops() - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block DEAD_BUBBLE_CORAL_FAN = register(new Block("dead_bubble_coral_fan", builder().requiresCorrectToolForDrops() - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block DEAD_FIRE_CORAL_FAN = register(new Block("dead_fire_coral_fan", builder().requiresCorrectToolForDrops() - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block DEAD_HORN_CORAL_FAN = register(new Block("dead_horn_coral_fan", builder().requiresCorrectToolForDrops() - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block TUBE_CORAL_FAN = register(new Block("tube_coral_fan", builder().pushReaction(PistonBehavior.DESTROY) - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block BRAIN_CORAL_FAN = register(new Block("brain_coral_fan", builder().pushReaction(PistonBehavior.DESTROY) - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block BUBBLE_CORAL_FAN = register(new Block("bubble_coral_fan", builder().pushReaction(PistonBehavior.DESTROY) - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block FIRE_CORAL_FAN = register(new Block("fire_coral_fan", builder().pushReaction(PistonBehavior.DESTROY) - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block HORN_CORAL_FAN = register(new Block("horn_coral_fan", builder().pushReaction(PistonBehavior.DESTROY) - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block DEAD_TUBE_CORAL_WALL_FAN = register(new Block("dead_tube_coral_wall_fan", builder().requiresCorrectToolForDrops() - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block DEAD_BRAIN_CORAL_WALL_FAN = register(new Block("dead_brain_coral_wall_fan", builder().requiresCorrectToolForDrops() - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block DEAD_BUBBLE_CORAL_WALL_FAN = register(new Block("dead_bubble_coral_wall_fan", builder().requiresCorrectToolForDrops() - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block DEAD_FIRE_CORAL_WALL_FAN = register(new Block("dead_fire_coral_wall_fan", builder().requiresCorrectToolForDrops() - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block DEAD_HORN_CORAL_WALL_FAN = register(new Block("dead_horn_coral_wall_fan", builder().requiresCorrectToolForDrops() - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block TUBE_CORAL_WALL_FAN = register(new Block("tube_coral_wall_fan", builder().pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block BRAIN_CORAL_WALL_FAN = register(new Block("brain_coral_wall_fan", builder().pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block BUBBLE_CORAL_WALL_FAN = register(new Block("bubble_coral_wall_fan", builder().pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block FIRE_CORAL_WALL_FAN = register(new Block("fire_coral_wall_fan", builder().pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block HORN_CORAL_WALL_FAN = register(new Block("horn_coral_wall_fan", builder().pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block SEA_PICKLE = register(new Block("sea_pickle", builder().pushReaction(PistonBehavior.DESTROY) - .intState(PICKLES) - .booleanState(WATERLOGGED))); + .intState(PICKLES) + .booleanState(WATERLOGGED))); public static final Block BLUE_ICE = register(new Block("blue_ice", builder().destroyTime(2.8f))); public static final Block CONDUIT = register(new Block("conduit", builder().setBlockEntity(BlockEntityType.CONDUIT).destroyTime(3.0f) - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block BAMBOO_SAPLING = register(new Block("bamboo_sapling", builder().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.BAMBOO))); public static final Block BAMBOO = register(new Block("bamboo", builder().destroyTime(1.0f).pushReaction(PistonBehavior.DESTROY) - .intState(AGE_1) - .enumState(BAMBOO_LEAVES) - .intState(STAGE))); + .intState(AGE_1) + .enumState(BAMBOO_LEAVES) + .intState(STAGE))); public static final Block POTTED_BAMBOO = register(new FlowerPotBlock("potted_bamboo", BAMBOO, builder().pushReaction(PistonBehavior.DESTROY))); public static final Block VOID_AIR = register(new Block("void_air", builder())); public static final Block CAVE_AIR = register(new Block("cave_air", builder())); public static final Block BUBBLE_COLUMN = register(new Block("bubble_column", builder().pushReaction(PistonBehavior.DESTROY) - .booleanState(DRAG))); + .booleanState(DRAG))); public static final Block POLISHED_GRANITE_STAIRS = register(new Block("polished_granite_stairs", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block SMOOTH_RED_SANDSTONE_STAIRS = register(new Block("smooth_red_sandstone_stairs", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block MOSSY_STONE_BRICK_STAIRS = register(new Block("mossy_stone_brick_stairs", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block POLISHED_DIORITE_STAIRS = register(new Block("polished_diorite_stairs", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block MOSSY_COBBLESTONE_STAIRS = register(new Block("mossy_cobblestone_stairs", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block END_STONE_BRICK_STAIRS = register(new Block("end_stone_brick_stairs", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block STONE_STAIRS = register(new Block("stone_stairs", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block SMOOTH_SANDSTONE_STAIRS = register(new Block("smooth_sandstone_stairs", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block SMOOTH_QUARTZ_STAIRS = register(new Block("smooth_quartz_stairs", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block GRANITE_STAIRS = register(new Block("granite_stairs", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block ANDESITE_STAIRS = register(new Block("andesite_stairs", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block RED_NETHER_BRICK_STAIRS = register(new Block("red_nether_brick_stairs", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block POLISHED_ANDESITE_STAIRS = register(new Block("polished_andesite_stairs", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block DIORITE_STAIRS = register(new Block("diorite_stairs", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block POLISHED_GRANITE_SLAB = register(new Block("polished_granite_slab", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block SMOOTH_RED_SANDSTONE_SLAB = register(new Block("smooth_red_sandstone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block MOSSY_STONE_BRICK_SLAB = register(new Block("mossy_stone_brick_slab", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block POLISHED_DIORITE_SLAB = register(new Block("polished_diorite_slab", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block MOSSY_COBBLESTONE_SLAB = register(new Block("mossy_cobblestone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block END_STONE_BRICK_SLAB = register(new Block("end_stone_brick_slab", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block SMOOTH_SANDSTONE_SLAB = register(new Block("smooth_sandstone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block SMOOTH_QUARTZ_SLAB = register(new Block("smooth_quartz_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block GRANITE_SLAB = register(new Block("granite_slab", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block ANDESITE_SLAB = register(new Block("andesite_slab", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block RED_NETHER_BRICK_SLAB = register(new Block("red_nether_brick_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block POLISHED_ANDESITE_SLAB = register(new Block("polished_andesite_slab", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block DIORITE_SLAB = register(new Block("diorite_slab", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block BRICK_WALL = register(new Block("brick_wall", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(EAST_WALL) - .enumState(NORTH_WALL) - .enumState(SOUTH_WALL) - .booleanState(UP) - .booleanState(WATERLOGGED) - .enumState(WEST_WALL))); + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL))); public static final Block PRISMARINE_WALL = register(new Block("prismarine_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(EAST_WALL) - .enumState(NORTH_WALL) - .enumState(SOUTH_WALL) - .booleanState(UP) - .booleanState(WATERLOGGED) - .enumState(WEST_WALL))); + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL))); public static final Block RED_SANDSTONE_WALL = register(new Block("red_sandstone_wall", builder().requiresCorrectToolForDrops().destroyTime(0.8f) - .enumState(EAST_WALL) - .enumState(NORTH_WALL) - .enumState(SOUTH_WALL) - .booleanState(UP) - .booleanState(WATERLOGGED) - .enumState(WEST_WALL))); + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL))); public static final Block MOSSY_STONE_BRICK_WALL = register(new Block("mossy_stone_brick_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(EAST_WALL) - .enumState(NORTH_WALL) - .enumState(SOUTH_WALL) - .booleanState(UP) - .booleanState(WATERLOGGED) - .enumState(WEST_WALL))); + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL))); public static final Block GRANITE_WALL = register(new Block("granite_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(EAST_WALL) - .enumState(NORTH_WALL) - .enumState(SOUTH_WALL) - .booleanState(UP) - .booleanState(WATERLOGGED) - .enumState(WEST_WALL))); + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL))); public static final Block STONE_BRICK_WALL = register(new Block("stone_brick_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(EAST_WALL) - .enumState(NORTH_WALL) - .enumState(SOUTH_WALL) - .booleanState(UP) - .booleanState(WATERLOGGED) - .enumState(WEST_WALL))); + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL))); public static final Block MUD_BRICK_WALL = register(new Block("mud_brick_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(EAST_WALL) - .enumState(NORTH_WALL) - .enumState(SOUTH_WALL) - .booleanState(UP) - .booleanState(WATERLOGGED) - .enumState(WEST_WALL))); + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL))); public static final Block NETHER_BRICK_WALL = register(new Block("nether_brick_wall", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(EAST_WALL) - .enumState(NORTH_WALL) - .enumState(SOUTH_WALL) - .booleanState(UP) - .booleanState(WATERLOGGED) - .enumState(WEST_WALL))); + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL))); public static final Block ANDESITE_WALL = register(new Block("andesite_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(EAST_WALL) - .enumState(NORTH_WALL) - .enumState(SOUTH_WALL) - .booleanState(UP) - .booleanState(WATERLOGGED) - .enumState(WEST_WALL))); + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL))); public static final Block RED_NETHER_BRICK_WALL = register(new Block("red_nether_brick_wall", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(EAST_WALL) - .enumState(NORTH_WALL) - .enumState(SOUTH_WALL) - .booleanState(UP) - .booleanState(WATERLOGGED) - .enumState(WEST_WALL))); + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL))); public static final Block SANDSTONE_WALL = register(new Block("sandstone_wall", builder().requiresCorrectToolForDrops().destroyTime(0.8f) - .enumState(EAST_WALL) - .enumState(NORTH_WALL) - .enumState(SOUTH_WALL) - .booleanState(UP) - .booleanState(WATERLOGGED) - .enumState(WEST_WALL))); + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL))); public static final Block END_STONE_BRICK_WALL = register(new Block("end_stone_brick_wall", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(EAST_WALL) - .enumState(NORTH_WALL) - .enumState(SOUTH_WALL) - .booleanState(UP) - .booleanState(WATERLOGGED) - .enumState(WEST_WALL))); + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL))); public static final Block DIORITE_WALL = register(new Block("diorite_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(EAST_WALL) - .enumState(NORTH_WALL) - .enumState(SOUTH_WALL) - .booleanState(UP) - .booleanState(WATERLOGGED) - .enumState(WEST_WALL))); + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL))); public static final Block SCAFFOLDING = register(new Block("scaffolding", builder().pushReaction(PistonBehavior.DESTROY) - .booleanState(BOTTOM) - .intState(STABILITY_DISTANCE) - .booleanState(WATERLOGGED))); + .booleanState(BOTTOM) + .intState(STABILITY_DISTANCE) + .booleanState(WATERLOGGED))); public static final Block LOOM = register(new Block("loom", builder().destroyTime(2.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block BARREL = register(new Block("barrel", builder().setBlockEntity(BlockEntityType.BARREL).destroyTime(2.5f) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) - .booleanState(OPEN))); + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) + .booleanState(OPEN))); public static final Block SMOKER = register(new Block("smoker", builder().setBlockEntity(BlockEntityType.SMOKER).requiresCorrectToolForDrops().destroyTime(3.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(LIT))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(LIT))); public static final Block BLAST_FURNACE = register(new Block("blast_furnace", builder().setBlockEntity(BlockEntityType.BLAST_FURNACE).requiresCorrectToolForDrops().destroyTime(3.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(LIT))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(LIT))); public static final Block CARTOGRAPHY_TABLE = register(new Block("cartography_table", builder().destroyTime(2.5f))); public static final Block FLETCHING_TABLE = register(new Block("fletching_table", builder().destroyTime(2.5f))); public static final Block GRINDSTONE = register(new Block("grindstone", builder().requiresCorrectToolForDrops().destroyTime(2.0f).pushReaction(PistonBehavior.BLOCK) - .enumState(ATTACH_FACE) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(ATTACH_FACE) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block LECTERN = register(new LecternBlock("lectern", builder().setBlockEntity(BlockEntityType.LECTERN).destroyTime(2.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(HAS_BOOK) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(HAS_BOOK) + .booleanState(POWERED))); public static final Block SMITHING_TABLE = register(new Block("smithing_table", builder().destroyTime(2.5f))); public static final Block STONECUTTER = register(new Block("stonecutter", builder().requiresCorrectToolForDrops().destroyTime(3.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST))); public static final Block BELL = register(new Block("bell", builder().setBlockEntity(BlockEntityType.BELL).requiresCorrectToolForDrops().destroyTime(5.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(BELL_ATTACHMENT) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(POWERED))); + .enumState(BELL_ATTACHMENT) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); public static final Block LANTERN = register(new Block("lantern", builder().requiresCorrectToolForDrops().destroyTime(3.5f).pushReaction(PistonBehavior.DESTROY) - .booleanState(HANGING) - .booleanState(WATERLOGGED))); + .booleanState(HANGING) + .booleanState(WATERLOGGED))); public static final Block SOUL_LANTERN = register(new Block("soul_lantern", builder().requiresCorrectToolForDrops().destroyTime(3.5f).pushReaction(PistonBehavior.DESTROY) - .booleanState(HANGING) - .booleanState(WATERLOGGED))); + .booleanState(HANGING) + .booleanState(WATERLOGGED))); public static final Block CAMPFIRE = register(new Block("campfire", builder().setBlockEntity(BlockEntityType.CAMPFIRE).destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(LIT) - .booleanState(SIGNAL_FIRE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(LIT) + .booleanState(SIGNAL_FIRE) + .booleanState(WATERLOGGED))); public static final Block SOUL_CAMPFIRE = register(new Block("soul_campfire", builder().setBlockEntity(BlockEntityType.CAMPFIRE).destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(LIT) - .booleanState(SIGNAL_FIRE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(LIT) + .booleanState(SIGNAL_FIRE) + .booleanState(WATERLOGGED))); public static final Block SWEET_BERRY_BUSH = register(new Block("sweet_berry_bush", builder().pushReaction(PistonBehavior.DESTROY) - .intState(AGE_3))); + .intState(AGE_3))); public static final Block WARPED_STEM = register(new Block("warped_stem", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block STRIPPED_WARPED_STEM = register(new Block("stripped_warped_stem", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block WARPED_HYPHAE = register(new Block("warped_hyphae", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block STRIPPED_WARPED_HYPHAE = register(new Block("stripped_warped_hyphae", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block WARPED_NYLIUM = register(new Block("warped_nylium", builder().requiresCorrectToolForDrops().destroyTime(0.4f))); public static final Block WARPED_FUNGUS = register(new Block("warped_fungus", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block WARPED_WART_BLOCK = register(new Block("warped_wart_block", builder().destroyTime(1.0f))); public static final Block WARPED_ROOTS = register(new Block("warped_roots", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block NETHER_SPROUTS = register(new Block("nether_sprouts", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block CRIMSON_STEM = register(new Block("crimson_stem", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block STRIPPED_CRIMSON_STEM = register(new Block("stripped_crimson_stem", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block CRIMSON_HYPHAE = register(new Block("crimson_hyphae", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block STRIPPED_CRIMSON_HYPHAE = register(new Block("stripped_crimson_hyphae", builder().destroyTime(2.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block CRIMSON_NYLIUM = register(new Block("crimson_nylium", builder().requiresCorrectToolForDrops().destroyTime(0.4f))); public static final Block CRIMSON_FUNGUS = register(new Block("crimson_fungus", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block SHROOMLIGHT = register(new Block("shroomlight", builder().destroyTime(1.0f))); public static final Block WEEPING_VINES = register(new Block("weeping_vines", builder().pushReaction(PistonBehavior.DESTROY) - .intState(AGE_25))); + .intState(AGE_25))); public static final Block WEEPING_VINES_PLANT = register(new Block("weeping_vines_plant", builder().pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.WEEPING_VINES))); public static final Block TWISTING_VINES = register(new Block("twisting_vines", builder().pushReaction(PistonBehavior.DESTROY) - .intState(AGE_25))); + .intState(AGE_25))); public static final Block TWISTING_VINES_PLANT = register(new Block("twisting_vines_plant", builder().pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.TWISTING_VINES))); public static final Block CRIMSON_ROOTS = register(new Block("crimson_roots", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block CRIMSON_PLANKS = register(new Block("crimson_planks", builder().destroyTime(2.0f))); public static final Block WARPED_PLANKS = register(new Block("warped_planks", builder().destroyTime(2.0f))); public static final Block CRIMSON_SLAB = register(new Block("crimson_slab", builder().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block WARPED_SLAB = register(new Block("warped_slab", builder().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block CRIMSON_PRESSURE_PLATE = register(new Block("crimson_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .booleanState(POWERED))); + .booleanState(POWERED))); public static final Block WARPED_PRESSURE_PLATE = register(new Block("warped_pressure_plate", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .booleanState(POWERED))); + .booleanState(POWERED))); public static final Block CRIMSON_FENCE = register(new Block("crimson_fence", builder().destroyTime(2.0f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block WARPED_FENCE = register(new Block("warped_fence", builder().destroyTime(2.0f) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block CRIMSON_TRAPDOOR = register(new TrapDoorBlock("crimson_trapdoor", builder().destroyTime(3.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .booleanState(OPEN) - .booleanState(POWERED) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); public static final Block WARPED_TRAPDOOR = register(new TrapDoorBlock("warped_trapdoor", builder().destroyTime(3.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .booleanState(OPEN) - .booleanState(POWERED) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); public static final Block CRIMSON_FENCE_GATE = register(new Block("crimson_fence_gate", builder().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(IN_WALL) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(IN_WALL) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block WARPED_FENCE_GATE = register(new Block("warped_fence_gate", builder().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(IN_WALL) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(IN_WALL) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block CRIMSON_STAIRS = register(new Block("crimson_stairs", builder().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block WARPED_STAIRS = register(new Block("warped_stairs", builder().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block CRIMSON_BUTTON = register(new Block("crimson_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .enumState(ATTACH_FACE) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(POWERED))); + .enumState(ATTACH_FACE) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); public static final Block WARPED_BUTTON = register(new Block("warped_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .enumState(ATTACH_FACE) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(POWERED))); + .enumState(ATTACH_FACE) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); public static final Block CRIMSON_DOOR = register(new DoorBlock("crimson_door", builder().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(DOUBLE_BLOCK_HALF) - .enumState(DOOR_HINGE) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF) + .enumState(DOOR_HINGE) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block WARPED_DOOR = register(new DoorBlock("warped_door", builder().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(DOUBLE_BLOCK_HALF) - .enumState(DOOR_HINGE) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF) + .enumState(DOOR_HINGE) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block CRIMSON_SIGN = register(new Block("crimson_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) - .intState(ROTATION_16) - .booleanState(WATERLOGGED))); + .intState(ROTATION_16) + .booleanState(WATERLOGGED))); public static final Block WARPED_SIGN = register(new Block("warped_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) - .intState(ROTATION_16) - .booleanState(WATERLOGGED))); + .intState(ROTATION_16) + .booleanState(WATERLOGGED))); public static final Block CRIMSON_WALL_SIGN = register(new Block("crimson_wall_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block WARPED_WALL_SIGN = register(new Block("warped_wall_sign", builder().setBlockEntity(BlockEntityType.SIGN).destroyTime(1.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block STRUCTURE_BLOCK = register(new Block("structure_block", builder().setBlockEntity(BlockEntityType.STRUCTURE_BLOCK).requiresCorrectToolForDrops().destroyTime(-1.0f) - .enumState(STRUCTUREBLOCK_MODE))); + .enumState(STRUCTUREBLOCK_MODE))); public static final Block JIGSAW = register(new Block("jigsaw", builder().setBlockEntity(BlockEntityType.JIGSAW).requiresCorrectToolForDrops().destroyTime(-1.0f) - .enumState(ORIENTATION, FrontAndTop.VALUES))); + .enumState(ORIENTATION, FrontAndTop.VALUES))); public static final Block COMPOSTER = register(new Block("composter", builder().destroyTime(0.6f) - .intState(LEVEL_COMPOSTER))); + .intState(LEVEL_COMPOSTER))); public static final Block TARGET = register(new Block("target", builder().destroyTime(0.5f) - .intState(POWER))); + .intState(POWER))); public static final Block BEE_NEST = register(new Block("bee_nest", builder().setBlockEntity(BlockEntityType.BEEHIVE).destroyTime(0.3f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .intState(LEVEL_HONEY))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .intState(LEVEL_HONEY))); public static final Block BEEHIVE = register(new Block("beehive", builder().setBlockEntity(BlockEntityType.BEEHIVE).destroyTime(0.6f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .intState(LEVEL_HONEY))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .intState(LEVEL_HONEY))); public static final Block HONEY_BLOCK = register(new HoneyBlock("honey_block", builder())); public static final Block HONEYCOMB_BLOCK = register(new Block("honeycomb_block", builder().destroyTime(0.6f))); public static final Block NETHERITE_BLOCK = register(new Block("netherite_block", builder().requiresCorrectToolForDrops().destroyTime(50.0f))); public static final Block ANCIENT_DEBRIS = register(new Block("ancient_debris", builder().requiresCorrectToolForDrops().destroyTime(30.0f))); public static final Block CRYING_OBSIDIAN = register(new Block("crying_obsidian", builder().requiresCorrectToolForDrops().destroyTime(50.0f))); public static final Block RESPAWN_ANCHOR = register(new Block("respawn_anchor", builder().requiresCorrectToolForDrops().destroyTime(50.0f) - .intState(RESPAWN_ANCHOR_CHARGES))); + .intState(RESPAWN_ANCHOR_CHARGES))); public static final Block POTTED_CRIMSON_FUNGUS = register(new FlowerPotBlock("potted_crimson_fungus", CRIMSON_FUNGUS, builder().pushReaction(PistonBehavior.DESTROY))); public static final Block POTTED_WARPED_FUNGUS = register(new FlowerPotBlock("potted_warped_fungus", WARPED_FUNGUS, builder().pushReaction(PistonBehavior.DESTROY))); public static final Block POTTED_CRIMSON_ROOTS = register(new FlowerPotBlock("potted_crimson_roots", CRIMSON_ROOTS, builder().pushReaction(PistonBehavior.DESTROY))); @@ -2196,257 +2265,257 @@ public final class Blocks { public static final Block LODESTONE = register(new Block("lodestone", builder().requiresCorrectToolForDrops().destroyTime(3.5f).pushReaction(PistonBehavior.BLOCK))); public static final Block BLACKSTONE = register(new Block("blackstone", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); public static final Block BLACKSTONE_STAIRS = register(new Block("blackstone_stairs", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block BLACKSTONE_WALL = register(new Block("blackstone_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(EAST_WALL) - .enumState(NORTH_WALL) - .enumState(SOUTH_WALL) - .booleanState(UP) - .booleanState(WATERLOGGED) - .enumState(WEST_WALL))); + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL))); public static final Block BLACKSTONE_SLAB = register(new Block("blackstone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block POLISHED_BLACKSTONE = register(new Block("polished_blackstone", builder().requiresCorrectToolForDrops().destroyTime(2.0f))); public static final Block POLISHED_BLACKSTONE_BRICKS = register(new Block("polished_blackstone_bricks", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); public static final Block CRACKED_POLISHED_BLACKSTONE_BRICKS = register(new Block("cracked_polished_blackstone_bricks", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); public static final Block CHISELED_POLISHED_BLACKSTONE = register(new Block("chiseled_polished_blackstone", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); public static final Block POLISHED_BLACKSTONE_BRICK_SLAB = register(new Block("polished_blackstone_brick_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block POLISHED_BLACKSTONE_BRICK_STAIRS = register(new Block("polished_blackstone_brick_stairs", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block POLISHED_BLACKSTONE_BRICK_WALL = register(new Block("polished_blackstone_brick_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(EAST_WALL) - .enumState(NORTH_WALL) - .enumState(SOUTH_WALL) - .booleanState(UP) - .booleanState(WATERLOGGED) - .enumState(WEST_WALL))); + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL))); public static final Block GILDED_BLACKSTONE = register(new Block("gilded_blackstone", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); public static final Block POLISHED_BLACKSTONE_STAIRS = register(new Block("polished_blackstone_stairs", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block POLISHED_BLACKSTONE_SLAB = register(new Block("polished_blackstone_slab", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block POLISHED_BLACKSTONE_PRESSURE_PLATE = register(new Block("polished_blackstone_pressure_plate", builder().requiresCorrectToolForDrops().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .booleanState(POWERED))); + .booleanState(POWERED))); public static final Block POLISHED_BLACKSTONE_BUTTON = register(new Block("polished_blackstone_button", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY) - .enumState(ATTACH_FACE) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(POWERED))); + .enumState(ATTACH_FACE) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(POWERED))); public static final Block POLISHED_BLACKSTONE_WALL = register(new Block("polished_blackstone_wall", builder().requiresCorrectToolForDrops().destroyTime(2.0f) - .enumState(EAST_WALL) - .enumState(NORTH_WALL) - .enumState(SOUTH_WALL) - .booleanState(UP) - .booleanState(WATERLOGGED) - .enumState(WEST_WALL))); + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL))); public static final Block CHISELED_NETHER_BRICKS = register(new Block("chiseled_nether_bricks", builder().requiresCorrectToolForDrops().destroyTime(2.0f))); public static final Block CRACKED_NETHER_BRICKS = register(new Block("cracked_nether_bricks", builder().requiresCorrectToolForDrops().destroyTime(2.0f))); public static final Block QUARTZ_BRICKS = register(new Block("quartz_bricks", builder().requiresCorrectToolForDrops().destroyTime(0.8f))); public static final Block CANDLE = register(new Block("candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) - .intState(CANDLES) - .booleanState(LIT) - .booleanState(WATERLOGGED))); + .intState(CANDLES) + .booleanState(LIT) + .booleanState(WATERLOGGED))); public static final Block WHITE_CANDLE = register(new Block("white_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) - .intState(CANDLES) - .booleanState(LIT) - .booleanState(WATERLOGGED))); + .intState(CANDLES) + .booleanState(LIT) + .booleanState(WATERLOGGED))); public static final Block ORANGE_CANDLE = register(new Block("orange_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) - .intState(CANDLES) - .booleanState(LIT) - .booleanState(WATERLOGGED))); + .intState(CANDLES) + .booleanState(LIT) + .booleanState(WATERLOGGED))); public static final Block MAGENTA_CANDLE = register(new Block("magenta_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) - .intState(CANDLES) - .booleanState(LIT) - .booleanState(WATERLOGGED))); + .intState(CANDLES) + .booleanState(LIT) + .booleanState(WATERLOGGED))); public static final Block LIGHT_BLUE_CANDLE = register(new Block("light_blue_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) - .intState(CANDLES) - .booleanState(LIT) - .booleanState(WATERLOGGED))); + .intState(CANDLES) + .booleanState(LIT) + .booleanState(WATERLOGGED))); public static final Block YELLOW_CANDLE = register(new Block("yellow_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) - .intState(CANDLES) - .booleanState(LIT) - .booleanState(WATERLOGGED))); + .intState(CANDLES) + .booleanState(LIT) + .booleanState(WATERLOGGED))); public static final Block LIME_CANDLE = register(new Block("lime_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) - .intState(CANDLES) - .booleanState(LIT) - .booleanState(WATERLOGGED))); + .intState(CANDLES) + .booleanState(LIT) + .booleanState(WATERLOGGED))); public static final Block PINK_CANDLE = register(new Block("pink_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) - .intState(CANDLES) - .booleanState(LIT) - .booleanState(WATERLOGGED))); + .intState(CANDLES) + .booleanState(LIT) + .booleanState(WATERLOGGED))); public static final Block GRAY_CANDLE = register(new Block("gray_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) - .intState(CANDLES) - .booleanState(LIT) - .booleanState(WATERLOGGED))); + .intState(CANDLES) + .booleanState(LIT) + .booleanState(WATERLOGGED))); public static final Block LIGHT_GRAY_CANDLE = register(new Block("light_gray_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) - .intState(CANDLES) - .booleanState(LIT) - .booleanState(WATERLOGGED))); + .intState(CANDLES) + .booleanState(LIT) + .booleanState(WATERLOGGED))); public static final Block CYAN_CANDLE = register(new Block("cyan_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) - .intState(CANDLES) - .booleanState(LIT) - .booleanState(WATERLOGGED))); + .intState(CANDLES) + .booleanState(LIT) + .booleanState(WATERLOGGED))); public static final Block PURPLE_CANDLE = register(new Block("purple_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) - .intState(CANDLES) - .booleanState(LIT) - .booleanState(WATERLOGGED))); + .intState(CANDLES) + .booleanState(LIT) + .booleanState(WATERLOGGED))); public static final Block BLUE_CANDLE = register(new Block("blue_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) - .intState(CANDLES) - .booleanState(LIT) - .booleanState(WATERLOGGED))); + .intState(CANDLES) + .booleanState(LIT) + .booleanState(WATERLOGGED))); public static final Block BROWN_CANDLE = register(new Block("brown_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) - .intState(CANDLES) - .booleanState(LIT) - .booleanState(WATERLOGGED))); + .intState(CANDLES) + .booleanState(LIT) + .booleanState(WATERLOGGED))); public static final Block GREEN_CANDLE = register(new Block("green_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) - .intState(CANDLES) - .booleanState(LIT) - .booleanState(WATERLOGGED))); + .intState(CANDLES) + .booleanState(LIT) + .booleanState(WATERLOGGED))); public static final Block RED_CANDLE = register(new Block("red_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) - .intState(CANDLES) - .booleanState(LIT) - .booleanState(WATERLOGGED))); + .intState(CANDLES) + .booleanState(LIT) + .booleanState(WATERLOGGED))); public static final Block BLACK_CANDLE = register(new Block("black_candle", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) - .intState(CANDLES) - .booleanState(LIT) - .booleanState(WATERLOGGED))); + .intState(CANDLES) + .booleanState(LIT) + .booleanState(WATERLOGGED))); public static final Block CANDLE_CAKE = register(new Block("candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.CAKE) - .booleanState(LIT))); + .booleanState(LIT))); public static final Block WHITE_CANDLE_CAKE = register(new Block("white_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.CAKE) - .booleanState(LIT))); + .booleanState(LIT))); public static final Block ORANGE_CANDLE_CAKE = register(new Block("orange_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.CAKE) - .booleanState(LIT))); + .booleanState(LIT))); public static final Block MAGENTA_CANDLE_CAKE = register(new Block("magenta_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.CAKE) - .booleanState(LIT))); + .booleanState(LIT))); public static final Block LIGHT_BLUE_CANDLE_CAKE = register(new Block("light_blue_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.CAKE) - .booleanState(LIT))); + .booleanState(LIT))); public static final Block YELLOW_CANDLE_CAKE = register(new Block("yellow_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.CAKE) - .booleanState(LIT))); + .booleanState(LIT))); public static final Block LIME_CANDLE_CAKE = register(new Block("lime_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.CAKE) - .booleanState(LIT))); + .booleanState(LIT))); public static final Block PINK_CANDLE_CAKE = register(new Block("pink_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.CAKE) - .booleanState(LIT))); + .booleanState(LIT))); public static final Block GRAY_CANDLE_CAKE = register(new Block("gray_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.CAKE) - .booleanState(LIT))); + .booleanState(LIT))); public static final Block LIGHT_GRAY_CANDLE_CAKE = register(new Block("light_gray_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.CAKE) - .booleanState(LIT))); + .booleanState(LIT))); public static final Block CYAN_CANDLE_CAKE = register(new Block("cyan_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.CAKE) - .booleanState(LIT))); + .booleanState(LIT))); public static final Block PURPLE_CANDLE_CAKE = register(new Block("purple_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.CAKE) - .booleanState(LIT))); + .booleanState(LIT))); public static final Block BLUE_CANDLE_CAKE = register(new Block("blue_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.CAKE) - .booleanState(LIT))); + .booleanState(LIT))); public static final Block BROWN_CANDLE_CAKE = register(new Block("brown_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.CAKE) - .booleanState(LIT))); + .booleanState(LIT))); public static final Block GREEN_CANDLE_CAKE = register(new Block("green_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.CAKE) - .booleanState(LIT))); + .booleanState(LIT))); public static final Block RED_CANDLE_CAKE = register(new Block("red_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.CAKE) - .booleanState(LIT))); + .booleanState(LIT))); public static final Block BLACK_CANDLE_CAKE = register(new Block("black_candle_cake", builder().destroyTime(0.5f).pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.CAKE) - .booleanState(LIT))); + .booleanState(LIT))); public static final Block AMETHYST_BLOCK = register(new Block("amethyst_block", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); public static final Block BUDDING_AMETHYST = register(new Block("budding_amethyst", builder().requiresCorrectToolForDrops().destroyTime(1.5f).pushReaction(PistonBehavior.DESTROY))); public static final Block AMETHYST_CLUSTER = register(new Block("amethyst_cluster", builder().destroyTime(1.5f).pushReaction(PistonBehavior.DESTROY) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) - .booleanState(WATERLOGGED))); + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) + .booleanState(WATERLOGGED))); public static final Block LARGE_AMETHYST_BUD = register(new Block("large_amethyst_bud", builder().destroyTime(1.5f).pushReaction(PistonBehavior.DESTROY) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) - .booleanState(WATERLOGGED))); + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) + .booleanState(WATERLOGGED))); public static final Block MEDIUM_AMETHYST_BUD = register(new Block("medium_amethyst_bud", builder().destroyTime(1.5f).pushReaction(PistonBehavior.DESTROY) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) - .booleanState(WATERLOGGED))); + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) + .booleanState(WATERLOGGED))); public static final Block SMALL_AMETHYST_BUD = register(new Block("small_amethyst_bud", builder().destroyTime(1.5f).pushReaction(PistonBehavior.DESTROY) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) - .booleanState(WATERLOGGED))); + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) + .booleanState(WATERLOGGED))); public static final Block TUFF = register(new Block("tuff", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); public static final Block TUFF_SLAB = register(new Block("tuff_slab", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block TUFF_STAIRS = register(new Block("tuff_stairs", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block TUFF_WALL = register(new Block("tuff_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(EAST_WALL) - .enumState(NORTH_WALL) - .enumState(SOUTH_WALL) - .booleanState(UP) - .booleanState(WATERLOGGED) - .enumState(WEST_WALL))); + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL))); public static final Block POLISHED_TUFF = register(new Block("polished_tuff", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); public static final Block POLISHED_TUFF_SLAB = register(new Block("polished_tuff_slab", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block POLISHED_TUFF_STAIRS = register(new Block("polished_tuff_stairs", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block POLISHED_TUFF_WALL = register(new Block("polished_tuff_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(EAST_WALL) - .enumState(NORTH_WALL) - .enumState(SOUTH_WALL) - .booleanState(UP) - .booleanState(WATERLOGGED) - .enumState(WEST_WALL))); + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL))); public static final Block CHISELED_TUFF = register(new Block("chiseled_tuff", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); public static final Block TUFF_BRICKS = register(new Block("tuff_bricks", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); public static final Block TUFF_BRICK_SLAB = register(new Block("tuff_brick_slab", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block TUFF_BRICK_STAIRS = register(new Block("tuff_brick_stairs", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block TUFF_BRICK_WALL = register(new Block("tuff_brick_wall", builder().requiresCorrectToolForDrops().destroyTime(1.5f) - .enumState(EAST_WALL) - .enumState(NORTH_WALL) - .enumState(SOUTH_WALL) - .booleanState(UP) - .booleanState(WATERLOGGED) - .enumState(WEST_WALL))); + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL))); public static final Block CHISELED_TUFF_BRICKS = register(new Block("chiseled_tuff_bricks", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); public static final Block CALCITE = register(new Block("calcite", builder().requiresCorrectToolForDrops().destroyTime(0.75f))); public static final Block TINTED_GLASS = register(new Block("tinted_glass", builder().destroyTime(0.3f))); public static final Block POWDER_SNOW = register(new Block("powder_snow", builder().destroyTime(0.25f))); public static final Block SCULK_SENSOR = register(new Block("sculk_sensor", builder().setBlockEntity(BlockEntityType.SCULK_SENSOR).destroyTime(1.5f) - .intState(POWER) - .enumState(SCULK_SENSOR_PHASE) - .booleanState(WATERLOGGED))); + .intState(POWER) + .enumState(SCULK_SENSOR_PHASE) + .booleanState(WATERLOGGED))); public static final Block CALIBRATED_SCULK_SENSOR = register(new Block("calibrated_sculk_sensor", builder().setBlockEntity(BlockEntityType.CALIBRATED_SCULK_SENSOR).destroyTime(1.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .intState(POWER) - .enumState(SCULK_SENSOR_PHASE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .intState(POWER) + .enumState(SCULK_SENSOR_PHASE) + .booleanState(WATERLOGGED))); public static final Block SCULK = register(new Block("sculk", builder().destroyTime(0.2f))); public static final Block SCULK_VEIN = register(new Block("sculk_vein", builder().destroyTime(0.2f).pushReaction(PistonBehavior.DESTROY) - .booleanState(DOWN) - .booleanState(EAST) - .booleanState(NORTH) - .booleanState(SOUTH) - .booleanState(UP) - .booleanState(WATERLOGGED) - .booleanState(WEST))); + .booleanState(DOWN) + .booleanState(EAST) + .booleanState(NORTH) + .booleanState(SOUTH) + .booleanState(UP) + .booleanState(WATERLOGGED) + .booleanState(WEST))); public static final Block SCULK_CATALYST = register(new Block("sculk_catalyst", builder().setBlockEntity(BlockEntityType.SCULK_CATALYST).destroyTime(3.0f) - .booleanState(BLOOM))); + .booleanState(BLOOM))); public static final Block SCULK_SHRIEKER = register(new Block("sculk_shrieker", builder().setBlockEntity(BlockEntityType.SCULK_SHRIEKER).destroyTime(3.0f) - .booleanState(CAN_SUMMON) - .booleanState(SHRIEKING) - .booleanState(WATERLOGGED))); + .booleanState(CAN_SUMMON) + .booleanState(SHRIEKING) + .booleanState(WATERLOGGED))); public static final Block COPPER_BLOCK = register(new Block("copper_block", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); public static final Block EXPOSED_COPPER = register(new Block("exposed_copper", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); public static final Block WEATHERED_COPPER = register(new Block("weathered_copper", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); @@ -2466,37 +2535,37 @@ public final class Blocks { public static final Block WAXED_EXPOSED_CHISELED_COPPER = register(new Block("waxed_exposed_chiseled_copper", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); public static final Block WAXED_CHISELED_COPPER = register(new Block("waxed_chiseled_copper", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); public static final Block OXIDIZED_CUT_COPPER_STAIRS = register(new Block("oxidized_cut_copper_stairs", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block WEATHERED_CUT_COPPER_STAIRS = register(new Block("weathered_cut_copper_stairs", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block EXPOSED_CUT_COPPER_STAIRS = register(new Block("exposed_cut_copper_stairs", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block CUT_COPPER_STAIRS = register(new Block("cut_copper_stairs", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block OXIDIZED_CUT_COPPER_SLAB = register(new Block("oxidized_cut_copper_slab", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block WEATHERED_CUT_COPPER_SLAB = register(new Block("weathered_cut_copper_slab", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block EXPOSED_CUT_COPPER_SLAB = register(new Block("exposed_cut_copper_slab", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block CUT_COPPER_SLAB = register(new Block("cut_copper_slab", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block WAXED_COPPER_BLOCK = register(new Block("waxed_copper_block", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); public static final Block WAXED_WEATHERED_COPPER = register(new Block("waxed_weathered_copper", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); public static final Block WAXED_EXPOSED_COPPER = register(new Block("waxed_exposed_copper", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); @@ -2506,281 +2575,281 @@ public final class Blocks { public static final Block WAXED_EXPOSED_CUT_COPPER = register(new Block("waxed_exposed_cut_copper", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); public static final Block WAXED_CUT_COPPER = register(new Block("waxed_cut_copper", builder().requiresCorrectToolForDrops().destroyTime(3.0f))); public static final Block WAXED_OXIDIZED_CUT_COPPER_STAIRS = register(new Block("waxed_oxidized_cut_copper_stairs", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block WAXED_WEATHERED_CUT_COPPER_STAIRS = register(new Block("waxed_weathered_cut_copper_stairs", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block WAXED_EXPOSED_CUT_COPPER_STAIRS = register(new Block("waxed_exposed_cut_copper_stairs", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block WAXED_CUT_COPPER_STAIRS = register(new Block("waxed_cut_copper_stairs", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block WAXED_OXIDIZED_CUT_COPPER_SLAB = register(new Block("waxed_oxidized_cut_copper_slab", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block WAXED_WEATHERED_CUT_COPPER_SLAB = register(new Block("waxed_weathered_cut_copper_slab", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block WAXED_EXPOSED_CUT_COPPER_SLAB = register(new Block("waxed_exposed_cut_copper_slab", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block WAXED_CUT_COPPER_SLAB = register(new Block("waxed_cut_copper_slab", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block COPPER_DOOR = register(new DoorBlock("copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(DOUBLE_BLOCK_HALF) - .enumState(DOOR_HINGE) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF) + .enumState(DOOR_HINGE) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block EXPOSED_COPPER_DOOR = register(new DoorBlock("exposed_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(DOUBLE_BLOCK_HALF) - .enumState(DOOR_HINGE) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF) + .enumState(DOOR_HINGE) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block OXIDIZED_COPPER_DOOR = register(new DoorBlock("oxidized_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(DOUBLE_BLOCK_HALF) - .enumState(DOOR_HINGE) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF) + .enumState(DOOR_HINGE) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block WEATHERED_COPPER_DOOR = register(new DoorBlock("weathered_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(DOUBLE_BLOCK_HALF) - .enumState(DOOR_HINGE) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF) + .enumState(DOOR_HINGE) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block WAXED_COPPER_DOOR = register(new DoorBlock("waxed_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(DOUBLE_BLOCK_HALF) - .enumState(DOOR_HINGE) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF) + .enumState(DOOR_HINGE) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block WAXED_EXPOSED_COPPER_DOOR = register(new DoorBlock("waxed_exposed_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(DOUBLE_BLOCK_HALF) - .enumState(DOOR_HINGE) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF) + .enumState(DOOR_HINGE) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block WAXED_OXIDIZED_COPPER_DOOR = register(new DoorBlock("waxed_oxidized_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(DOUBLE_BLOCK_HALF) - .enumState(DOOR_HINGE) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF) + .enumState(DOOR_HINGE) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block WAXED_WEATHERED_COPPER_DOOR = register(new DoorBlock("waxed_weathered_copper_door", builder().requiresCorrectToolForDrops().destroyTime(3.0f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(DOUBLE_BLOCK_HALF) - .enumState(DOOR_HINGE) - .booleanState(OPEN) - .booleanState(POWERED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF) + .enumState(DOOR_HINGE) + .booleanState(OPEN) + .booleanState(POWERED))); public static final Block COPPER_TRAPDOOR = register(new TrapDoorBlock("copper_trapdoor", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .booleanState(OPEN) - .booleanState(POWERED) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); public static final Block EXPOSED_COPPER_TRAPDOOR = register(new TrapDoorBlock("exposed_copper_trapdoor", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .booleanState(OPEN) - .booleanState(POWERED) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); public static final Block OXIDIZED_COPPER_TRAPDOOR = register(new TrapDoorBlock("oxidized_copper_trapdoor", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .booleanState(OPEN) - .booleanState(POWERED) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); public static final Block WEATHERED_COPPER_TRAPDOOR = register(new TrapDoorBlock("weathered_copper_trapdoor", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .booleanState(OPEN) - .booleanState(POWERED) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); public static final Block WAXED_COPPER_TRAPDOOR = register(new TrapDoorBlock("waxed_copper_trapdoor", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .booleanState(OPEN) - .booleanState(POWERED) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); public static final Block WAXED_EXPOSED_COPPER_TRAPDOOR = register(new TrapDoorBlock("waxed_exposed_copper_trapdoor", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .booleanState(OPEN) - .booleanState(POWERED) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); public static final Block WAXED_OXIDIZED_COPPER_TRAPDOOR = register(new TrapDoorBlock("waxed_oxidized_copper_trapdoor", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .booleanState(OPEN) - .booleanState(POWERED) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); public static final Block WAXED_WEATHERED_COPPER_TRAPDOOR = register(new TrapDoorBlock("waxed_weathered_copper_trapdoor", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .booleanState(OPEN) - .booleanState(POWERED) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .booleanState(OPEN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); public static final Block COPPER_GRATE = register(new Block("copper_grate", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block EXPOSED_COPPER_GRATE = register(new Block("exposed_copper_grate", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block WEATHERED_COPPER_GRATE = register(new Block("weathered_copper_grate", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block OXIDIZED_COPPER_GRATE = register(new Block("oxidized_copper_grate", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block WAXED_COPPER_GRATE = register(new Block("waxed_copper_grate", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block WAXED_EXPOSED_COPPER_GRATE = register(new Block("waxed_exposed_copper_grate", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block WAXED_WEATHERED_COPPER_GRATE = register(new Block("waxed_weathered_copper_grate", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block WAXED_OXIDIZED_COPPER_GRATE = register(new Block("waxed_oxidized_copper_grate", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block COPPER_BULB = register(new Block("copper_bulb", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .booleanState(LIT) - .booleanState(POWERED))); + .booleanState(LIT) + .booleanState(POWERED))); public static final Block EXPOSED_COPPER_BULB = register(new Block("exposed_copper_bulb", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .booleanState(LIT) - .booleanState(POWERED))); + .booleanState(LIT) + .booleanState(POWERED))); public static final Block WEATHERED_COPPER_BULB = register(new Block("weathered_copper_bulb", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .booleanState(LIT) - .booleanState(POWERED))); + .booleanState(LIT) + .booleanState(POWERED))); public static final Block OXIDIZED_COPPER_BULB = register(new Block("oxidized_copper_bulb", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .booleanState(LIT) - .booleanState(POWERED))); + .booleanState(LIT) + .booleanState(POWERED))); public static final Block WAXED_COPPER_BULB = register(new Block("waxed_copper_bulb", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .booleanState(LIT) - .booleanState(POWERED))); + .booleanState(LIT) + .booleanState(POWERED))); public static final Block WAXED_EXPOSED_COPPER_BULB = register(new Block("waxed_exposed_copper_bulb", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .booleanState(LIT) - .booleanState(POWERED))); + .booleanState(LIT) + .booleanState(POWERED))); public static final Block WAXED_WEATHERED_COPPER_BULB = register(new Block("waxed_weathered_copper_bulb", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .booleanState(LIT) - .booleanState(POWERED))); + .booleanState(LIT) + .booleanState(POWERED))); public static final Block WAXED_OXIDIZED_COPPER_BULB = register(new Block("waxed_oxidized_copper_bulb", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .booleanState(LIT) - .booleanState(POWERED))); + .booleanState(LIT) + .booleanState(POWERED))); public static final Block LIGHTNING_ROD = register(new Block("lightning_rod", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) - .booleanState(POWERED) - .booleanState(WATERLOGGED))); + .enumState(FACING, Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.UP, Direction.DOWN) + .booleanState(POWERED) + .booleanState(WATERLOGGED))); public static final Block POINTED_DRIPSTONE = register(new Block("pointed_dripstone", builder().destroyTime(1.5f).pushReaction(PistonBehavior.DESTROY) - .enumState(DRIPSTONE_THICKNESS) - .enumState(VERTICAL_DIRECTION, Direction.UP, Direction.DOWN) - .booleanState(WATERLOGGED))); + .enumState(DRIPSTONE_THICKNESS) + .enumState(VERTICAL_DIRECTION, Direction.UP, Direction.DOWN) + .booleanState(WATERLOGGED))); public static final Block DRIPSTONE_BLOCK = register(new Block("dripstone_block", builder().requiresCorrectToolForDrops().destroyTime(1.5f))); public static final Block CAVE_VINES = register(new Block("cave_vines", builder().pushReaction(PistonBehavior.DESTROY) - .intState(AGE_25) - .booleanState(BERRIES))); + .intState(AGE_25) + .booleanState(BERRIES))); public static final Block CAVE_VINES_PLANT = register(new Block("cave_vines_plant", builder().pushReaction(PistonBehavior.DESTROY).pickItem(() -> Items.GLOW_BERRIES) - .booleanState(BERRIES))); + .booleanState(BERRIES))); public static final Block SPORE_BLOSSOM = register(new Block("spore_blossom", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block AZALEA = register(new Block("azalea", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block FLOWERING_AZALEA = register(new Block("flowering_azalea", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block MOSS_CARPET = register(new Block("moss_carpet", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY))); public static final Block PINK_PETALS = register(new Block("pink_petals", builder().pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .intState(FLOWER_AMOUNT))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .intState(FLOWER_AMOUNT))); public static final Block MOSS_BLOCK = register(new Block("moss_block", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY))); public static final Block BIG_DRIPLEAF = register(new Block("big_dripleaf", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(TILT) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(TILT) + .booleanState(WATERLOGGED))); public static final Block BIG_DRIPLEAF_STEM = register(new Block("big_dripleaf_stem", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block SMALL_DRIPLEAF = register(new Block("small_dripleaf", builder().pushReaction(PistonBehavior.DESTROY) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(DOUBLE_BLOCK_HALF) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(DOUBLE_BLOCK_HALF) + .booleanState(WATERLOGGED))); public static final Block HANGING_ROOTS = register(new Block("hanging_roots", builder().pushReaction(PistonBehavior.DESTROY) - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); public static final Block ROOTED_DIRT = register(new Block("rooted_dirt", builder().destroyTime(0.5f))); public static final Block MUD = register(new Block("mud", builder().destroyTime(0.5f))); public static final Block DEEPSLATE = register(new Block("deepslate", builder().requiresCorrectToolForDrops().destroyTime(3.0f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block COBBLED_DEEPSLATE = register(new Block("cobbled_deepslate", builder().requiresCorrectToolForDrops().destroyTime(3.5f))); public static final Block COBBLED_DEEPSLATE_STAIRS = register(new Block("cobbled_deepslate_stairs", builder().requiresCorrectToolForDrops().destroyTime(3.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block COBBLED_DEEPSLATE_SLAB = register(new Block("cobbled_deepslate_slab", builder().requiresCorrectToolForDrops().destroyTime(3.5f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block COBBLED_DEEPSLATE_WALL = register(new Block("cobbled_deepslate_wall", builder().requiresCorrectToolForDrops().destroyTime(3.5f) - .enumState(EAST_WALL) - .enumState(NORTH_WALL) - .enumState(SOUTH_WALL) - .booleanState(UP) - .booleanState(WATERLOGGED) - .enumState(WEST_WALL))); + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL))); public static final Block POLISHED_DEEPSLATE = register(new Block("polished_deepslate", builder().requiresCorrectToolForDrops().destroyTime(3.5f))); public static final Block POLISHED_DEEPSLATE_STAIRS = register(new Block("polished_deepslate_stairs", builder().requiresCorrectToolForDrops().destroyTime(3.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block POLISHED_DEEPSLATE_SLAB = register(new Block("polished_deepslate_slab", builder().requiresCorrectToolForDrops().destroyTime(3.5f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block POLISHED_DEEPSLATE_WALL = register(new Block("polished_deepslate_wall", builder().requiresCorrectToolForDrops().destroyTime(3.5f) - .enumState(EAST_WALL) - .enumState(NORTH_WALL) - .enumState(SOUTH_WALL) - .booleanState(UP) - .booleanState(WATERLOGGED) - .enumState(WEST_WALL))); + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL))); public static final Block DEEPSLATE_TILES = register(new Block("deepslate_tiles", builder().requiresCorrectToolForDrops().destroyTime(3.5f))); public static final Block DEEPSLATE_TILE_STAIRS = register(new Block("deepslate_tile_stairs", builder().requiresCorrectToolForDrops().destroyTime(3.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block DEEPSLATE_TILE_SLAB = register(new Block("deepslate_tile_slab", builder().requiresCorrectToolForDrops().destroyTime(3.5f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block DEEPSLATE_TILE_WALL = register(new Block("deepslate_tile_wall", builder().requiresCorrectToolForDrops().destroyTime(3.5f) - .enumState(EAST_WALL) - .enumState(NORTH_WALL) - .enumState(SOUTH_WALL) - .booleanState(UP) - .booleanState(WATERLOGGED) - .enumState(WEST_WALL))); + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL))); public static final Block DEEPSLATE_BRICKS = register(new Block("deepslate_bricks", builder().requiresCorrectToolForDrops().destroyTime(3.5f))); public static final Block DEEPSLATE_BRICK_STAIRS = register(new Block("deepslate_brick_stairs", builder().requiresCorrectToolForDrops().destroyTime(3.5f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .enumState(HALF) - .enumState(STAIRS_SHAPE) - .booleanState(WATERLOGGED))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .enumState(HALF) + .enumState(STAIRS_SHAPE) + .booleanState(WATERLOGGED))); public static final Block DEEPSLATE_BRICK_SLAB = register(new Block("deepslate_brick_slab", builder().requiresCorrectToolForDrops().destroyTime(3.5f) - .enumState(SLAB_TYPE) - .booleanState(WATERLOGGED))); + .enumState(SLAB_TYPE) + .booleanState(WATERLOGGED))); public static final Block DEEPSLATE_BRICK_WALL = register(new Block("deepslate_brick_wall", builder().requiresCorrectToolForDrops().destroyTime(3.5f) - .enumState(EAST_WALL) - .enumState(NORTH_WALL) - .enumState(SOUTH_WALL) - .booleanState(UP) - .booleanState(WATERLOGGED) - .enumState(WEST_WALL))); + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) + .booleanState(UP) + .booleanState(WATERLOGGED) + .enumState(WEST_WALL))); public static final Block CHISELED_DEEPSLATE = register(new Block("chiseled_deepslate", builder().requiresCorrectToolForDrops().destroyTime(3.5f))); public static final Block CRACKED_DEEPSLATE_BRICKS = register(new Block("cracked_deepslate_bricks", builder().requiresCorrectToolForDrops().destroyTime(3.5f))); public static final Block CRACKED_DEEPSLATE_TILES = register(new Block("cracked_deepslate_tiles", builder().requiresCorrectToolForDrops().destroyTime(3.5f))); public static final Block INFESTED_DEEPSLATE = register(new Block("infested_deepslate", builder().destroyTime(1.5f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block SMOOTH_BASALT = register(new Block("smooth_basalt", builder().requiresCorrectToolForDrops().destroyTime(1.25f))); public static final Block RAW_IRON_BLOCK = register(new Block("raw_iron_block", builder().requiresCorrectToolForDrops().destroyTime(5.0f))); public static final Block RAW_COPPER_BLOCK = register(new Block("raw_copper_block", builder().requiresCorrectToolForDrops().destroyTime(5.0f))); @@ -2788,30 +2857,39 @@ public final class Blocks { public static final Block POTTED_AZALEA_BUSH = register(new FlowerPotBlock("potted_azalea_bush", AZALEA, builder().pushReaction(PistonBehavior.DESTROY))); public static final Block POTTED_FLOWERING_AZALEA_BUSH = register(new FlowerPotBlock("potted_flowering_azalea_bush", FLOWERING_AZALEA, builder().pushReaction(PistonBehavior.DESTROY))); public static final Block OCHRE_FROGLIGHT = register(new Block("ochre_froglight", builder().destroyTime(0.3f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block VERDANT_FROGLIGHT = register(new Block("verdant_froglight", builder().destroyTime(0.3f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block PEARLESCENT_FROGLIGHT = register(new Block("pearlescent_froglight", builder().destroyTime(0.3f) - .enumState(AXIS, Axis.VALUES))); + .enumState(AXIS, Axis.VALUES))); public static final Block FROGSPAWN = register(new Block("frogspawn", builder().pushReaction(PistonBehavior.DESTROY))); public static final Block REINFORCED_DEEPSLATE = register(new Block("reinforced_deepslate", builder().destroyTime(55.0f))); public static final Block DECORATED_POT = register(new Block("decorated_pot", builder().setBlockEntity(BlockEntityType.DECORATED_POT).pushReaction(PistonBehavior.DESTROY) - .booleanState(CRACKED) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(WATERLOGGED))); + .booleanState(CRACKED) + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(WATERLOGGED))); public static final Block CRAFTER = register(new Block("crafter", builder().setBlockEntity(BlockEntityType.CRAFTER).destroyTime(1.5f) - .booleanState(CRAFTING) - .enumState(ORIENTATION, FrontAndTop.VALUES) - .booleanState(TRIGGERED))); + .booleanState(CRAFTING) + .enumState(ORIENTATION, FrontAndTop.VALUES) + .booleanState(TRIGGERED))); public static final Block TRIAL_SPAWNER = register(new Block("trial_spawner", builder().setBlockEntity(BlockEntityType.TRIAL_SPAWNER).destroyTime(50.0f) - .booleanState(OMINOUS) - .enumState(TRIAL_SPAWNER_STATE))); + .booleanState(OMINOUS) + .enumState(TRIAL_SPAWNER_STATE))); public static final Block VAULT = register(new Block("vault", builder().setBlockEntity(BlockEntityType.VAULT).destroyTime(50.0f) - .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) - .booleanState(OMINOUS) - .enumState(VAULT_STATE))); + .enumState(HORIZONTAL_FACING, Direction.NORTH, Direction.SOUTH, Direction.WEST, Direction.EAST) + .booleanState(OMINOUS) + .enumState(VAULT_STATE))); public static final Block HEAVY_CORE = register(new Block("heavy_core", builder().destroyTime(10.0f) - .booleanState(WATERLOGGED))); + .booleanState(WATERLOGGED))); + public static final Block PALE_MOSS_BLOCK = register(new Block("pale_moss_block", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY))); + public static final Block PALE_MOSS_CARPET = register(new Block("pale_moss_carpet", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) + .booleanState(BOTTOM) + .enumState(EAST_WALL) + .enumState(NORTH_WALL) + .enumState(SOUTH_WALL) + .enumState(WEST_WALL))); + public static final Block PALE_HANGING_MOSS = register(new Block("pale_hanging_moss", builder().destroyTime(0.1f).pushReaction(PistonBehavior.DESTROY) + .booleanState(TIP))); private static T register(T block) { block.setJavaId(BlockRegistries.JAVA_BLOCKS.get().size()); diff --git a/core/src/main/java/org/geysermc/geyser/level/block/property/Properties.java b/core/src/main/java/org/geysermc/geyser/level/block/property/Properties.java index 7efa2ef80..3e5f1b510 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/property/Properties.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/property/Properties.java @@ -47,6 +47,7 @@ public final class Properties { public static final BooleanProperty INVERTED = BooleanProperty.create("inverted"); public static final BooleanProperty IN_WALL = BooleanProperty.create("in_wall"); public static final BooleanProperty LIT = BooleanProperty.create("lit"); + public static final BooleanProperty TIP = BooleanProperty.create("tip"); public static final BooleanProperty LOCKED = BooleanProperty.create("locked"); public static final BooleanProperty OCCUPIED = BooleanProperty.create("occupied"); public static final BooleanProperty OPEN = BooleanProperty.create("open"); @@ -142,5 +143,6 @@ public final class Properties { public static final BooleanProperty CRAFTING = BooleanProperty.create("crafting"); public static final BasicEnumProperty TRIAL_SPAWNER_STATE = BasicEnumProperty.create("trial_spawner_state", "inactive", "waiting_for_players", "active", "waiting_for_reward_ejection", "ejecting_reward", "cooldown"); public static final BasicEnumProperty VAULT_STATE = BasicEnumProperty.create("vault_state", "inactive", "active", "unlocking", "ejecting"); + public static final BasicEnumProperty CREAKING = BasicEnumProperty.create("creaking", "disabled", "dormant", "active"); public static final BooleanProperty OMINOUS = BooleanProperty.create("ominous"); } diff --git a/core/src/main/java/org/geysermc/geyser/level/physics/CollisionManager.java b/core/src/main/java/org/geysermc/geyser/level/physics/CollisionManager.java index a0fb312b4..c5f986499 100644 --- a/core/src/main/java/org/geysermc/geyser/level/physics/CollisionManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/physics/CollisionManager.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.level.physics; import lombok.Getter; import lombok.Setter; +import net.kyori.adventure.util.TriState; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.GenericMath; import org.cloudburstmc.math.vector.Vector3d; @@ -153,11 +154,10 @@ public class CollisionManager { * the two versions. Will also send corrected movement packets back to Bedrock if they collide with pistons. * * @param bedrockPosition the current Bedrock position of the client - * @param onGround whether the Bedrock player is on the ground * @param teleported whether the Bedrock player has teleported to a new position. If true, movement correction is skipped. * @return the position to send to the Java server, or null to cancel sending the packet */ - public @Nullable Vector3d adjustBedrockPosition(Vector3f bedrockPosition, boolean onGround, boolean teleported) { + public @Nullable CollisionResult adjustBedrockPosition(Vector3f bedrockPosition, boolean teleported) { PistonCache pistonCache = session.getPistonCache(); // Bedrock clients tend to fall off of honey blocks, so we need to teleport them to the new position if (pistonCache.isPlayerAttachedToHoney()) { @@ -176,7 +176,7 @@ public class CollisionManager { playerBoundingBox.setMiddleY(position.getY() + playerBoundingBox.getSizeY() / 2); playerBoundingBox.setMiddleZ(position.getZ()); - return playerBoundingBox.getBottomCenter(); + return new CollisionResult(playerBoundingBox.getBottomCenter(), TriState.NOT_SET); } Vector3d startingPos = playerBoundingBox.getBottomCenter(); @@ -198,13 +198,13 @@ public class CollisionManager { position = playerBoundingBox.getBottomCenter(); - boolean newOnGround = adjustedMovement.getY() != movement.getY() && movement.getY() < 0 || onGround; + boolean onGround = (adjustedMovement.getY() != movement.getY() && movement.getY() < 0) || isOnGround(); // Send corrected position to Bedrock if they differ by too much to prevent de-syncs - if (onGround != newOnGround || movement.distanceSquared(adjustedMovement) > INCORRECT_MOVEMENT_THRESHOLD) { + if (movement.distanceSquared(adjustedMovement) > INCORRECT_MOVEMENT_THRESHOLD) { PlayerEntity playerEntity = session.getPlayerEntity(); // Client will dismount if on a vehicle if (playerEntity.getVehicle() == null && pistonCache.getPlayerMotion().equals(Vector3f.ZERO) && !pistonCache.isPlayerSlimeCollision()) { - playerEntity.moveAbsolute(position.toFloat(), playerEntity.getYaw(), playerEntity.getPitch(), playerEntity.getHeadYaw(), newOnGround, true); + playerEntity.moveAbsolute(position.toFloat(), playerEntity.getYaw(), playerEntity.getPitch(), playerEntity.getHeadYaw(), onGround, true); } } @@ -213,7 +213,7 @@ public class CollisionManager { position = Vector3d.from(position.getX(), Double.parseDouble(DECIMAL_FORMAT.format(position.getY())), position.getZ()); } - return position; + return new CollisionResult(position, TriState.byBoolean(onGround)); } // TODO: This makes the player look upwards for some reason, rotation values must be wrong @@ -415,44 +415,38 @@ public class CollisionManager { return BlockUtils.getCollision(blockId); } - /** - * @return true if the block located at the player's floor position plus 1 would intersect with the player, - * were they not sneaking - */ - public boolean mustPlayerSneakHere() { - return checkPose(EntityDefinitions.PLAYER.height()); - } - - /** - * @return true if the block located at the player's floor position plus 1 would intersect with the player, - * were they not crawling - */ - public boolean mustPlayerCrawlHere() { - return checkPose(PlayerEntity.SNEAKING_POSE_HEIGHT); - } - - /** - * @param height check and see if this height is invalid in the current player position - */ - private boolean checkPose(float height) { - Vector3i position = session.getPlayerEntity().getPosition().toInt(); - BlockCollision collision = BlockUtils.getCollisionAt(session, position); - if (collision != null) { - // Determine, if the player's bounding box *were* at full height, if it would intersect with the block - // at the current location. - double originalY = playerBoundingBox.getMiddleY(); - double originalHeight = playerBoundingBox.getSizeY(); - double standingY = originalY - (originalHeight / 2.0) + (height / 2.0); - - playerBoundingBox.setSizeY(EntityDefinitions.PLAYER.height()); - playerBoundingBox.setMiddleY(standingY); - boolean result = collision.checkIntersection(position, playerBoundingBox); - result |= session.getPistonCache().checkCollision(position, playerBoundingBox); - playerBoundingBox.setSizeY(originalHeight); - playerBoundingBox.setMiddleY(originalY); - return result; + private boolean isOnGround() { + // Someone smarter than me at collisions plz check this. + Vector3d bottomCenter = playerBoundingBox.getBottomCenter(); + Vector3i groundPos = Vector3i.from(bottomCenter.getX(), bottomCenter.getY() - 1, bottomCenter.getZ()); + BlockCollision collision = BlockUtils.getCollisionAt(session, groundPos); + if (collision == null) { + return false; // Probably air. } - return false; + + // Hack to not check below the player + playerBoundingBox.setSizeY(playerBoundingBox.getSizeY() - 0.001); + playerBoundingBox.setMiddleY(playerBoundingBox.getMiddleY() + 0.002); + + boolean intersected = collision.checkIntersection(groundPos.getX(), groundPos.getY(), groundPos.getZ(), playerBoundingBox); + + playerBoundingBox.setSizeY(playerBoundingBox.getSizeY() + 0.001); + playerBoundingBox.setMiddleY(playerBoundingBox.getMiddleY() - 0.002); + + boolean result; + if (intersected) { + result = true; + } else { + // Hack to check slightly below the player + playerBoundingBox.setSizeY(playerBoundingBox.getSizeY() + 0.001); + playerBoundingBox.setMiddleY(playerBoundingBox.getMiddleY() - 0.002); + + result = collision.checkIntersection(groundPos.getX(), groundPos.getY(), groundPos.getZ(), playerBoundingBox); + + playerBoundingBox.setSizeY(playerBoundingBox.getSizeY() - 0.001); + playerBoundingBox.setMiddleY(playerBoundingBox.getMiddleY() + 0.002); + } + return result; } /** diff --git a/core/src/main/java/org/geysermc/geyser/util/Ordered.java b/core/src/main/java/org/geysermc/geyser/level/physics/CollisionResult.java similarity index 82% rename from core/src/main/java/org/geysermc/geyser/util/Ordered.java rename to core/src/main/java/org/geysermc/geyser/level/physics/CollisionResult.java index 08ff5df72..3c8271cd9 100644 --- a/core/src/main/java/org/geysermc/geyser/util/Ordered.java +++ b/core/src/main/java/org/geysermc/geyser/level/physics/CollisionResult.java @@ -23,11 +23,13 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.util; +package org.geysermc.geyser.level.physics; + +import net.kyori.adventure.util.TriState; +import org.cloudburstmc.math.vector.Vector3d; /** - * Represents anything that could be tracked like a enum, without also creating a name and enum-wide array. + * Holds the result of a collision check. */ -public interface Ordered { - int ordinal(); +public record CollisionResult(Vector3d correctedMovement, TriState onGround) { } diff --git a/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java b/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java index cdbeef143..15aa8bc2c 100644 --- a/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java +++ b/core/src/main/java/org/geysermc/geyser/network/CodecProcessor.java @@ -31,11 +31,13 @@ import org.cloudburstmc.protocol.bedrock.codec.BedrockCodecHelper; import org.cloudburstmc.protocol.bedrock.codec.BedrockPacketSerializer; import org.cloudburstmc.protocol.bedrock.codec.v291.serializer.MobArmorEquipmentSerializer_v291; import org.cloudburstmc.protocol.bedrock.codec.v291.serializer.MobEquipmentSerializer_v291; +import org.cloudburstmc.protocol.bedrock.codec.v291.serializer.MoveEntityAbsoluteSerializer_v291; import org.cloudburstmc.protocol.bedrock.codec.v291.serializer.PlayerHotbarSerializer_v291; import org.cloudburstmc.protocol.bedrock.codec.v291.serializer.SetEntityLinkSerializer_v291; import org.cloudburstmc.protocol.bedrock.codec.v390.serializer.PlayerSkinSerializer_v390; import org.cloudburstmc.protocol.bedrock.codec.v407.serializer.InventoryContentSerializer_v407; import org.cloudburstmc.protocol.bedrock.codec.v407.serializer.InventorySlotSerializer_v407; +import org.cloudburstmc.protocol.bedrock.codec.v419.serializer.MovePlayerSerializer_v419; import org.cloudburstmc.protocol.bedrock.codec.v486.serializer.BossEventSerializer_v486; import org.cloudburstmc.protocol.bedrock.codec.v557.serializer.SetEntityDataSerializer_v557; import org.cloudburstmc.protocol.bedrock.codec.v662.serializer.SetEntityMotionSerializer_v662; @@ -67,15 +69,18 @@ import org.cloudburstmc.protocol.bedrock.packet.MapCreateLockedCopyPacket; import org.cloudburstmc.protocol.bedrock.packet.MapInfoRequestPacket; import org.cloudburstmc.protocol.bedrock.packet.MobArmorEquipmentPacket; import org.cloudburstmc.protocol.bedrock.packet.MobEquipmentPacket; +import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket; +import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket; import org.cloudburstmc.protocol.bedrock.packet.MultiplayerSettingsPacket; import org.cloudburstmc.protocol.bedrock.packet.NpcRequestPacket; import org.cloudburstmc.protocol.bedrock.packet.PhotoInfoRequestPacket; import org.cloudburstmc.protocol.bedrock.packet.PhotoTransferPacket; -import org.cloudburstmc.protocol.bedrock.packet.PlayerAuthInputPacket; import org.cloudburstmc.protocol.bedrock.packet.PlayerHotbarPacket; +import org.cloudburstmc.protocol.bedrock.packet.PlayerInputPacket; import org.cloudburstmc.protocol.bedrock.packet.PlayerSkinPacket; import org.cloudburstmc.protocol.bedrock.packet.PurchaseReceiptPacket; import org.cloudburstmc.protocol.bedrock.packet.RefreshEntitlementsPacket; +import org.cloudburstmc.protocol.bedrock.packet.RiderJumpPacket; import org.cloudburstmc.protocol.bedrock.packet.ScriptMessagePacket; import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket; import org.cloudburstmc.protocol.bedrock.packet.SetEntityLinkPacket; @@ -190,6 +195,20 @@ class CodecProcessor { } }; + private static final BedrockPacketSerializer MOVE_PLAYER_SERIALIZER = new MovePlayerSerializer_v419() { + @Override + public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, MovePlayerPacket packet) { + throw new IllegalArgumentException("Client cannot send MovePlayerPacket in server-auth movement environment!"); + } + }; + + private static final BedrockPacketSerializer MOVE_ENTITY_SERIALIZER = new MoveEntityAbsoluteSerializer_v291() { + @Override + public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, MoveEntityAbsolutePacket packet) { + throw new IllegalArgumentException("Client cannot send MoveEntityAbsolutePacket in server-auth movement environment!"); + } + }; + /** * Serializer that does nothing when trying to deserialize BossEventPacket since it is not used from the client. */ @@ -318,7 +337,6 @@ class CodecProcessor { .updateSerializer(ClientCheatAbilityPacket.class, ILLEGAL_SERIALIZER) .updateSerializer(CraftingEventPacket.class, ILLEGAL_SERIALIZER) // Illegal unusued serverbound packets that relate to unused features - .updateSerializer(PlayerAuthInputPacket.class, ILLEGAL_SERIALIZER) .updateSerializer(ClientCacheBlobStatusPacket.class, ILLEGAL_SERIALIZER) .updateSerializer(SubClientLoginPacket.class, ILLEGAL_SERIALIZER) .updateSerializer(SubChunkRequestPacket.class, ILLEGAL_SERIALIZER) @@ -334,6 +352,10 @@ class CodecProcessor { // Illegal when serverbound due to Geyser specific setup .updateSerializer(InventoryContentPacket.class, inventoryContentSerializer) .updateSerializer(InventorySlotPacket.class, inventorySlotSerializer) + .updateSerializer(MovePlayerPacket.class, MOVE_PLAYER_SERIALIZER) + .updateSerializer(MoveEntityAbsolutePacket.class, MOVE_ENTITY_SERIALIZER) + .updateSerializer(RiderJumpPacket.class, ILLEGAL_SERIALIZER) + .updateSerializer(PlayerInputPacket.class, ILLEGAL_SERIALIZER) // Ignored only when serverbound .updateSerializer(BossEventPacket.class, BOSS_EVENT_SERIALIZER) .updateSerializer(MobArmorEquipmentPacket.class, is712OrAbove ? MOB_ARMOR_EQUIPMENT_SERIALIZER_V712 : MOB_ARMOR_EQUIPMENT_SERIALIZER_V291) diff --git a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java index 48f1dee5f..1ac38aa35 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.network; import io.netty.buffer.Unpooled; +import org.cloudburstmc.math.vector.Vector2f; import org.cloudburstmc.protocol.bedrock.BedrockDisconnectReasons; import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; import org.cloudburstmc.protocol.bedrock.codec.compat.BedrockCompat; @@ -38,9 +39,9 @@ import org.cloudburstmc.protocol.bedrock.netty.codec.compression.ZlibCompression import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; import org.cloudburstmc.protocol.bedrock.packet.LoginPacket; import org.cloudburstmc.protocol.bedrock.packet.ModalFormResponsePacket; -import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket; import org.cloudburstmc.protocol.bedrock.packet.NetworkSettingsPacket; import org.cloudburstmc.protocol.bedrock.packet.PlayStatusPacket; +import org.cloudburstmc.protocol.bedrock.packet.PlayerAuthInputPacket; import org.cloudburstmc.protocol.bedrock.packet.RequestNetworkSettingsPacket; import org.cloudburstmc.protocol.bedrock.packet.ResourcePackChunkDataPacket; import org.cloudburstmc.protocol.bedrock.packet.ResourcePackChunkRequestPacket; @@ -290,8 +291,9 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { } @Override - public PacketSignal handle(MovePlayerPacket packet) { - if (session.isLoggingIn()) { + public PacketSignal handle(PlayerAuthInputPacket packet) { + // This doesn't catch rotation, but for a niche case I don't exactly want to cache rotation... + if (session.isLoggingIn() && !packet.getMotion().equals(Vector2f.ZERO)) { SetTitlePacket titlePacket = new SetTitlePacket(); titlePacket.setType(SetTitlePacket.Type.ACTIONBAR); titlePacket.setText(GeyserLocale.getPlayerLocaleString("geyser.auth.login.wait", session.locale())); diff --git a/core/src/main/java/org/geysermc/geyser/registry/Registries.java b/core/src/main/java/org/geysermc/geyser/registry/Registries.java index 0d286d5c3..b0ae0d6aa 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.registry; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; @@ -42,13 +43,13 @@ import org.geysermc.geyser.registry.loader.BlockEntityRegistryLoader; import org.geysermc.geyser.registry.loader.ParticleTypesRegistryLoader; import org.geysermc.geyser.registry.loader.PotionMixRegistryLoader; import org.geysermc.geyser.registry.loader.ProviderRegistryLoader; -import org.geysermc.geyser.registry.loader.RecipeRegistryLoader; import org.geysermc.geyser.registry.loader.RegistryLoaders; import org.geysermc.geyser.registry.loader.SoundEventsRegistryLoader; import org.geysermc.geyser.registry.loader.SoundRegistryLoader; import org.geysermc.geyser.registry.loader.SoundTranslatorRegistryLoader; import org.geysermc.geyser.registry.populator.ItemRegistryPopulator; import org.geysermc.geyser.registry.populator.PacketRegistryPopulator; +import org.geysermc.geyser.registry.populator.TagRegistryPopulator; import org.geysermc.geyser.registry.provider.ProviderSupplier; import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.geyser.registry.type.ParticleMapping; @@ -62,13 +63,11 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; import org.geysermc.mcprotocollib.protocol.data.game.level.event.LevelEvent; import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ParticleType; -import org.geysermc.mcprotocollib.protocol.data.game.recipe.RecipeType; import java.util.ArrayList; import java.util.EnumMap; import java.util.HashSet; import java.util.IdentityHashMap; -import java.util.List; import java.util.Map; import java.util.Set; @@ -159,13 +158,18 @@ public final class Registries { /** * A versioned registry holding all the recipes, with the net ID being the key, and {@link GeyserRecipe} as the value. */ - public static final SimpleMappedDeferredRegistry> RECIPES = SimpleMappedDeferredRegistry.create("mappings/recipes.nbt", RecipeRegistryLoader::new); + //public static final SimpleMappedDeferredRegistry> RECIPES = SimpleMappedDeferredRegistry.create("mappings/recipes.nbt", RecipeRegistryLoader::new); /** * A mapped registry holding {@link ResourcePack}'s with the pack uuid as keys. */ public static final SimpleMappedDeferredRegistry RESOURCE_PACKS = SimpleMappedDeferredRegistry.create(GeyserImpl.getInstance().packDirectory(), RegistryLoaders.RESOURCE_PACKS); + /** + * A versioned registry holding most Bedrock tags, with the Java item list (sorted) being the key, and the tag name as the value. + */ + public static final VersionedRegistry> TAGS = VersionedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new)); + /** * A mapped registry holding sound identifiers to their corresponding {@link SoundMapping}. */ @@ -195,7 +199,7 @@ public final class Registries { BLOCK_ENTITIES.load(); PARTICLES.load(); // load potion mixes later - RECIPES.load(); + //RECIPES.load(); RESOURCE_PACKS.load(); SOUNDS.load(); SOUND_LEVEL_EVENTS.load(); @@ -205,6 +209,7 @@ public final class Registries { public static void populate() { PacketRegistryPopulator.populate(); ItemRegistryPopulator.populate(); + TagRegistryPopulator.populate(); // potion mixes depend on other registries POTION_MIXES.load(); diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/RecipeRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/RecipeRegistryLoader.java index f1d0c456f..4cbd2ea47 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/RecipeRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/RecipeRegistryLoader.java @@ -27,26 +27,15 @@ package org.geysermc.geyser.registry.loader; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import it.unimi.dsi.fastutil.Pair; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import org.cloudburstmc.nbt.NBTInputStream; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtType; -import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.recipe.GeyserRecipe; -import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe; -import org.geysermc.geyser.inventory.recipe.GeyserShapelessRecipe; -import org.geysermc.geyser.text.GeyserLocale; -import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodec; import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodecHelper; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.recipe.Ingredient; -import org.geysermc.mcprotocollib.protocol.data.game.recipe.RecipeType; -import java.io.DataInputStream; -import java.io.InputStream; import java.util.ArrayList; import java.util.Base64; import java.util.List; @@ -56,38 +45,41 @@ import java.util.Map; * Populates the recipe registry with some recipes that Java does not send, to ensure they show up as intended * in the recipe book. */ -public final class RecipeRegistryLoader implements RegistryLoader>> { +public abstract class RecipeRegistryLoader implements RegistryLoader>> { - @Override - public Map> load(String input) { - Map> deserializedRecipes = new Object2ObjectOpenHashMap<>(); +// @Override +// public Map> load(String input) { +// if (true) { +// return Collections.emptyMap(); +// } +// Map> deserializedRecipes = new Object2ObjectOpenHashMap<>(); +// +// List recipes; +// try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow("mappings/recipes.nbt")) { +// try (NBTInputStream nbtStream = new NBTInputStream(new DataInputStream(stream))) { +// recipes = ((NbtMap) nbtStream.readTag()).getList("recipes", NbtType.COMPOUND); +// } +// } catch (Exception e) { +// throw new AssertionError(GeyserLocale.getLocaleStringLog("geyser.toolbox.fail.runtime_java"), e); +// } +// +// MinecraftCodecHelper helper = MinecraftCodec.CODEC.getHelperFactory().get(); +// for (NbtMap recipeCollection : recipes) { +// var pair = getRecipes(recipeCollection, helper); +// deserializedRecipes.put(pair.key(), pair.value()); +// } +// return deserializedRecipes; +// } - List recipes; - try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow("mappings/recipes.nbt")) { - try (NBTInputStream nbtStream = new NBTInputStream(new DataInputStream(stream))) { - recipes = ((NbtMap) nbtStream.readTag()).getList("recipes", NbtType.COMPOUND); - } - } catch (Exception e) { - throw new AssertionError(GeyserLocale.getLocaleStringLog("geyser.toolbox.fail.runtime_java"), e); - } - - MinecraftCodecHelper helper = MinecraftCodec.CODEC.getHelperFactory().get(); - for (NbtMap recipeCollection : recipes) { - var pair = getRecipes(recipeCollection, helper); - deserializedRecipes.put(pair.key(), pair.value()); - } - return deserializedRecipes; - } - - private static Pair> getRecipes(NbtMap recipes, MinecraftCodecHelper helper) { - List typedRecipes = recipes.getList("recipes", NbtType.COMPOUND); - RecipeType recipeType = RecipeType.from(recipes.getInt("recipe_type", -1)); - if (recipeType == RecipeType.CRAFTING_SPECIAL_TIPPEDARROW) { - return Pair.of(recipeType, getShapedRecipes(typedRecipes, helper)); - } else { - return Pair.of(recipeType, getShapelessRecipes(typedRecipes, helper)); - } - } +// private static Pair> getRecipes(NbtMap recipes, MinecraftCodecHelper helper) { +// List typedRecipes = recipes.getList("recipes", NbtType.COMPOUND); +// RecipeType recipeType = RecipeType.from(recipes.getInt("recipe_type", -1)); +// if (recipeType == RecipeType.CRAFTING_SPECIAL_TIPPEDARROW) { +// return Pair.of(recipeType, getShapedRecipes(typedRecipes, helper)); +// } else { +// return Pair.of(recipeType, getShapelessRecipes(typedRecipes, helper)); +// } +// } private static List getShapelessRecipes(List recipes, MinecraftCodecHelper helper) { List deserializedRecipes = new ObjectArrayList<>(recipes.size()); @@ -96,9 +88,9 @@ public final class RecipeRegistryLoader implements RegistryLoader rawInputs = recipe.getList("inputs", NbtType.COMPOUND); Ingredient[] javaInputs = new Ingredient[rawInputs.size()]; for (int i = 0; i < rawInputs.size(); i++) { - javaInputs[i] = new Ingredient(new ItemStack[] {toItemStack(rawInputs.get(i), helper)}); + //javaInputs[i] = new Ingredient(new ItemStack[] {toItemStack(rawInputs.get(i), helper)}); } - deserializedRecipes.add(new GeyserShapelessRecipe(javaInputs, output)); + //deserializedRecipes.add(new GeyserShapelessRecipe(javaInputs, output)); } return deserializedRecipes; } @@ -121,10 +113,10 @@ public final class RecipeRegistryLoader implements RegistryLoader javaOnlyItems, Remapper remapper) { + record PaletteVersion(String version, int protocolVersion, Map javaOnlyItems, Remapper remapper) { public PaletteVersion(String version, int protocolVersion) { this(version, protocolVersion, Collections.emptyMap(), (item, mapping) -> mapping); @@ -109,11 +110,17 @@ public class ItemRegistryPopulator { } public static void populate() { + List bundles = List.of(Items.BUNDLE, Items.BLACK_BUNDLE, Items.BLUE_BUNDLE, Items.BROWN_BUNDLE, Items.CYAN_BUNDLE, Items.GRAY_BUNDLE, + Items.GREEN_BUNDLE, Items.LIGHT_BLUE_BUNDLE, Items.LIGHT_GRAY_BUNDLE, Items.LIME_BUNDLE, Items.MAGENTA_BUNDLE, Items.ORANGE_BUNDLE, Items.RED_BUNDLE, + Items.PINK_BUNDLE, Items.PURPLE_BUNDLE, Items.WHITE_BUNDLE, Items.YELLOW_BUNDLE); + Map pre1_21_2Items = new HashMap<>(); + bundles.forEach(bundle -> pre1_21_2Items.put(bundle, Items.SHULKER_SHELL)); + List paletteVersions = new ArrayList<>(3); - paletteVersions.add(new PaletteVersion("1_20_80", Bedrock_v671.CODEC.getProtocolVersion(), Collections.emptyMap(), Conversion685_671::remapItem)); - paletteVersions.add(new PaletteVersion("1_21_0", Bedrock_v685.CODEC.getProtocolVersion(), Collections.emptyMap(), Conversion712_685::remapItem)); - paletteVersions.add(new PaletteVersion("1_21_20", Bedrock_v712.CODEC.getProtocolVersion(), Collections.emptyMap(), Conversion729_712::remapItem)); - paletteVersions.add(new PaletteVersion("1_21_30", Bedrock_v729.CODEC.getProtocolVersion(), Collections.emptyMap(), Conversion748_729::remapItem)); + paletteVersions.add(new PaletteVersion("1_20_80", Bedrock_v671.CODEC.getProtocolVersion(), pre1_21_2Items, Conversion685_671::remapItem)); + paletteVersions.add(new PaletteVersion("1_21_0", Bedrock_v685.CODEC.getProtocolVersion(), pre1_21_2Items, Conversion712_685::remapItem)); + paletteVersions.add(new PaletteVersion("1_21_20", Bedrock_v712.CODEC.getProtocolVersion(), pre1_21_2Items, Conversion729_712::remapItem)); + paletteVersions.add(new PaletteVersion("1_21_30", Bedrock_v729.CODEC.getProtocolVersion(), pre1_21_2Items, Conversion748_729::remapItem)); paletteVersions.add(new PaletteVersion("1_21_40", Bedrock_v748.CODEC.getProtocolVersion())); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); @@ -227,7 +234,7 @@ public class ItemRegistryPopulator { Set javaOnlyItems = new ObjectOpenHashSet<>(); Collections.addAll(javaOnlyItems, Items.SPECTRAL_ARROW, Items.DEBUG_STICK, - Items.KNOWLEDGE_BOOK, Items.TIPPED_ARROW, Items.BUNDLE); + Items.KNOWLEDGE_BOOK, Items.TIPPED_ARROW); if (!customItemsAllowed) { javaOnlyItems.add(Items.FURNACE_MINECART); } @@ -243,9 +250,9 @@ public class ItemRegistryPopulator { throw new RuntimeException("Extra item in mappings? " + entry.getKey()); } GeyserMappingItem mappingItem; - String replacementItem = palette.javaOnlyItems().get(javaItem); + Item replacementItem = palette.javaOnlyItems().get(javaItem); if (replacementItem != null) { - mappingItem = items.get(replacementItem); // java only item, a java id fallback has been provided + mappingItem = items.get(replacementItem.javaIdentifier()); // java only item, a java id fallback has been provided } else { // check if any mapping changes need to be made on this version mappingItem = palette.remapper().remap(javaItem, entry.getValue()); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/TagRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/TagRegistryPopulator.java new file mode 100644 index 000000000..bee207a00 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/TagRegistryPopulator.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2024 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.registry.populator; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import it.unimi.dsi.fastutil.Hash; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap; +import it.unimi.dsi.fastutil.objects.ObjectIntPair; +import org.cloudburstmc.protocol.bedrock.codec.v671.Bedrock_v671; +import org.cloudburstmc.protocol.bedrock.codec.v685.Bedrock_v685; +import org.cloudburstmc.protocol.bedrock.codec.v712.Bedrock_v712; +import org.cloudburstmc.protocol.bedrock.codec.v729.Bedrock_v729; +import org.cloudburstmc.protocol.bedrock.codec.v748.Bedrock_v748; +import org.geysermc.geyser.GeyserBootstrap; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.item.type.Item; +import org.geysermc.geyser.registry.Registries; +import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.registry.type.ItemMappings; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +public final class TagRegistryPopulator { + private static final Gson GSON = new GsonBuilder().create(); // temporary + + public static void populate() { + Hash.Strategy hashStrategy = new Hash.Strategy<>() { + // Necessary so arrays can actually be compared + @Override + public int hashCode(int[] o) { + return Arrays.hashCode(o); + } + + @Override + public boolean equals(int[] a, int[] b) { + return Arrays.equals(a, b); + } + }; + + List> paletteVersions = List.of( + ObjectIntPair.of("1_20_80", Bedrock_v671.CODEC.getProtocolVersion()), + ObjectIntPair.of("1_21_0", Bedrock_v685.CODEC.getProtocolVersion()), + ObjectIntPair.of("1_21_20", Bedrock_v712.CODEC.getProtocolVersion()), + ObjectIntPair.of("1_21_30", Bedrock_v729.CODEC.getProtocolVersion()), + ObjectIntPair.of("1_21_40", Bedrock_v748.CODEC.getProtocolVersion()) + ); + TypeToken>> type = new TypeToken<>() {}; + + GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); + + for (var palette : paletteVersions) { + ItemMappings mappings = Registries.ITEMS.forVersion(palette.rightInt()); + + Map> bedrockTags; + try (InputStream stream = bootstrap.getResourceOrThrow(String.format("bedrock/item_tags.%s.json", palette.left()))) { + bedrockTags = GSON.fromJson(new InputStreamReader(stream), type); + } catch (Exception e) { + throw new AssertionError("Unable to load Bedrock runtime item IDs", e); + } + + var javaItemsToBedrockTag = new Object2ObjectOpenCustomHashMap(hashStrategy); + + for (var entry : bedrockTags.entrySet()) { + List value = entry.getValue(); + if (value.isEmpty() || value.size() == 1) { + // For our usecase, we don't need this. Empty values are worthless; one value can just be a reference + // to the item itself, instead of the tag. + continue; + } + + // In some cases, the int list will need to be minimized + IntList javaNetworkIds = new IntArrayList(value.size()); + for (int i = 0; i < value.size(); i++) { + String bedrockIdentifier = value.get(i); + Item javaItem = Registries.JAVA_ITEM_IDENTIFIERS.get(bedrockIdentifier); + if (javaItem == null) { + // Time to search the long way around. + for (ItemMapping mapping : mappings.getItems()) { + if (mapping.getBedrockIdentifier().equals(bedrockIdentifier)) { + javaItem = mapping.getJavaItem(); + break; + } + } + } + if (javaItem == null) { + // Triggers for Bedrock-only spawn eggs. We don't care. + continue; + } + + javaNetworkIds.add(javaItem.javaId()); + } + + int[] javaNetworkIdArray = javaNetworkIds.toIntArray(); + // Sort IDs so equality checks just have to match if each is equal and not necessarily an order difference. + Arrays.sort(javaNetworkIdArray); + + javaItemsToBedrockTag.put(javaNetworkIdArray, entry.getKey()); + } + + javaItemsToBedrockTag.trim(); + Registries.TAGS.register(palette.rightInt(), javaItemsToBedrockTag); + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index b8a991013..ef6261ead 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -29,6 +29,7 @@ import com.google.gson.Gson; import com.google.gson.JsonObject; import io.netty.channel.Channel; import io.netty.channel.EventLoop; +import it.unimi.dsi.fastutil.Pair; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; @@ -77,13 +78,13 @@ import org.cloudburstmc.protocol.bedrock.data.command.SoftEnumUpdateType; import org.cloudburstmc.protocol.bedrock.data.definitions.DimensionDefinition; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; +import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.CraftingRecipeData; import org.cloudburstmc.protocol.bedrock.packet.AvailableEntityIdentifiersPacket; import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; import org.cloudburstmc.protocol.bedrock.packet.BiomeDefinitionListPacket; import org.cloudburstmc.protocol.bedrock.packet.CameraPresetsPacket; import org.cloudburstmc.protocol.bedrock.packet.ChunkRadiusUpdatedPacket; import org.cloudburstmc.protocol.bedrock.packet.ClientboundCloseFormPacket; -import org.cloudburstmc.protocol.bedrock.packet.CraftingDataPacket; import org.cloudburstmc.protocol.bedrock.packet.CreativeContentPacket; import org.cloudburstmc.protocol.bedrock.packet.DimensionDataPacket; import org.cloudburstmc.protocol.bedrock.packet.EmoteListPacket; @@ -142,6 +143,7 @@ import org.geysermc.geyser.impl.camera.GeyserCameraData; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.PlayerInventory; import org.geysermc.geyser.inventory.recipe.GeyserRecipe; +import org.geysermc.geyser.inventory.recipe.GeyserSmithingRecipe; import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.BlockItem; @@ -161,6 +163,7 @@ import org.geysermc.geyser.session.cache.ChunkCache; import org.geysermc.geyser.session.cache.EntityCache; import org.geysermc.geyser.session.cache.EntityEffectCache; import org.geysermc.geyser.session.cache.FormCache; +import org.geysermc.geyser.session.cache.InputCache; import org.geysermc.geyser.session.cache.LodestoneCache; import org.geysermc.geyser.session.cache.PistonCache; import org.geysermc.geyser.session.cache.PreferencesCache; @@ -178,6 +181,7 @@ import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.ChunkUtils; import org.geysermc.geyser.util.EntityUtils; +import org.geysermc.geyser.util.InventoryUtils; import org.geysermc.geyser.util.LoginEncryptionUtils; import org.geysermc.geyser.util.MinecraftAuthLogger; import org.geysermc.mcprotocollib.auth.GameProfile; @@ -191,7 +195,6 @@ import org.geysermc.mcprotocollib.network.event.session.SessionAdapter; import org.geysermc.mcprotocollib.network.packet.Packet; import org.geysermc.mcprotocollib.network.tcp.TcpClientSession; import org.geysermc.mcprotocollib.network.tcp.TcpSession; -import org.geysermc.mcprotocollib.protocol.ClientListener; import org.geysermc.mcprotocollib.protocol.MinecraftConstants; import org.geysermc.mcprotocollib.protocol.MinecraftProtocol; import org.geysermc.mcprotocollib.protocol.data.ProtocolState; @@ -203,16 +206,15 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.HandPreference; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerAction; import org.geysermc.mcprotocollib.protocol.data.game.setting.ChatVisibility; +import org.geysermc.mcprotocollib.protocol.data.game.setting.ParticleStatus; import org.geysermc.mcprotocollib.protocol.data.game.setting.SkinPart; import org.geysermc.mcprotocollib.protocol.data.game.statistic.CustomStatistic; import org.geysermc.mcprotocollib.protocol.data.game.statistic.Statistic; import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundClientInformationPacket; -import org.geysermc.mcprotocollib.protocol.packet.configuration.clientbound.ClientboundFinishConfigurationPacket; -import org.geysermc.mcprotocollib.protocol.packet.configuration.serverbound.ServerboundFinishConfigurationPacket; import org.geysermc.mcprotocollib.protocol.packet.handshake.serverbound.ClientIntentionPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundChatCommandSignedPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundChatPacket; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundClientTickEndPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket; @@ -254,7 +256,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { private final EventLoop eventLoop; @Setter private AuthData authData; - @Setter private BedrockClientData clientData; /** * Used for Floodgate skin uploading @@ -278,6 +279,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { private final EntityCache entityCache; private final EntityEffectCache effectCache; private final FormCache formCache; + private final InputCache inputCache; private final LodestoneCache lodestoneCache; private final PistonCache pistonCache; private final PreferencesCache preferencesCache; @@ -312,7 +314,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { private final AtomicInteger itemNetId = new AtomicInteger(2); @Setter - private ScheduledFuture craftingGridFuture; + private ScheduledFuture containerOutputFuture; /** * Stores session collision @@ -443,21 +445,22 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { private Entity mouseoverEntity; /** - * Stores all Java recipes by recipe identifier, and matches them to all possible Bedrock recipe identifiers. - * They are not 1:1, since Bedrock can have multiple recipes for the same Java recipe. + * Stores all Java recipes by ID, and matches them to all possible Bedrock recipe identifiers. */ - private final Map> javaToBedrockRecipeIds; + private final Int2ObjectMap> javaToBedrockRecipeIds; + private final Int2ObjectMap craftingRecipes; @Setter - private Int2ObjectMap craftingRecipes; + private Pair lastCreatedRecipe = null; // TODO try to prevent sending duplicate recipes private final AtomicInteger lastRecipeNetId; /** * Saves a list of all stonecutter recipes, for use in a stonecutter inventory. - * The key is the Java ID of the item; the values are all the possible outputs' Java IDs sorted by their string identifier + * The key is the Bedrock recipe net ID; the values are their respective output and button ID. */ @Setter private Int2ObjectMap stonecutterRecipes; + private final List smithingRecipes = new ArrayList<>(); /** * Whether to work around 1.13's different behavior in villager trading menus. @@ -526,18 +529,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Setter private boolean placedBucket; - /** - * Used to send a movement packet every three seconds if the player hasn't moved. Prevents timeouts when AFK in certain instances. - */ - @Setter - private long lastMovementTimestamp = System.currentTimeMillis(); - - /** - * Used to send a ServerboundMoveVehiclePacket for every PlayerInputPacket after idling on a boat/horse for more than 100ms - */ - @Setter - private long lastVehicleMoveTimestamp = System.currentTimeMillis(); - /** * Counts how many ticks have occurred since an arm animation started. * -1 means there is no active arm swing; -2 means an arm swing will start in a tick. @@ -675,13 +666,14 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { this.entityCache = new EntityCache(this); this.effectCache = new EntityEffectCache(); this.formCache = new FormCache(this); + this.inputCache = new InputCache(this); this.lodestoneCache = new LodestoneCache(); this.pistonCache = new PistonCache(this); this.preferencesCache = new PreferencesCache(this); this.registryCache = new RegistryCache(this); this.skullCache = new SkullCache(this); this.structureBlockCache = new StructureBlockCache(); - this.tagCache = new TagCache(); + this.tagCache = new TagCache(this); this.worldCache = new WorldCache(this); this.cameraData = new GeyserCameraData(this); this.entityData = new GeyserEntityData(this); @@ -696,8 +688,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { this.playerInventory = new PlayerInventory(); this.openInventory = null; this.craftingRecipes = new Int2ObjectOpenHashMap<>(); - this.javaToBedrockRecipeIds = new Object2ObjectOpenHashMap<>(); - this.lastRecipeNetId = new AtomicInteger(1); + this.javaToBedrockRecipeIds = new Int2ObjectOpenHashMap<>(); + this.lastRecipeNetId = new AtomicInteger(InventoryUtils.LAST_RECIPE_NET_ID + 1); this.spawned = false; this.loggedIn = false; @@ -769,12 +761,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { creativePacket.setContents(this.itemMappings.getCreativeItems()); upstream.sendPacket(creativePacket); - // Potion mixes are registered by default, as they are needed to be able to put ingredients into the brewing stand. - CraftingDataPacket craftingDataPacket = new CraftingDataPacket(); - craftingDataPacket.setCleanRecipes(true); - craftingDataPacket.getPotionMixData().addAll(Registries.POTION_MIXES.forVersion(this.upstream.getProtocolVersion())); - upstream.sendPacket(craftingDataPacket); - PlayStatusPacket playStatusPacket = new PlayStatusPacket(); playStatusPacket.setStatus(PlayStatusPacket.Status.PLAYER_SPAWN); upstream.sendPacket(playStatusPacket); @@ -1091,6 +1077,11 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { // Download and load the language for the player MinecraftLocale.downloadAndLoadLocale(locale); + +// if (sentSpawnPacket && !GameProtocol.isPre1_21_2(GeyserSession.this)) { +// // Possible form to close. +// upstream.sendPacket(new ClientboundCloseFormPacket()); +// } } @Override @@ -1269,18 +1260,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { protected void tick() { try { pistonCache.tick(); - // Check to see if the player's position needs updating - a position update should be sent once every 3 seconds - if (spawned && (System.currentTimeMillis() - lastMovementTimestamp) > 3000) { - // Recalculate in case something else changed position - Vector3d position = collisionManager.adjustBedrockPosition(playerEntity.getPosition(), playerEntity.isOnGround(), false); - // A null return value cancels the packet - if (position != null) { - ServerboundMovePlayerPosPacket packet = new ServerboundMovePlayerPosPacket(playerEntity.isOnGround(), - position.getX(), position.getY(), position.getZ()); - sendDownstreamGamePacket(packet); - } - lastMovementTimestamp = System.currentTimeMillis(); - } if (worldBorder.isResizing()) { worldBorder.resize(); @@ -1338,6 +1317,12 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { armAnimationTicks = -1; } } + + if (spawned) { + // Could move this to the PlayerAuthInput translator, in the event the player lags + // but this will work once we implement matching Java custom tick cycles + sendDownstreamGamePacket(ServerboundClientTickEndPacket.INSTANCE); + } } catch (Throwable throwable) { throwable.printStackTrace(); } @@ -1396,14 +1381,28 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { } public void setSwimming(boolean swimming) { - if (swimming) { + if (!swimming && playerEntity.getFlag(EntityFlag.CRAWLING)) { + // Do not update bounding box. + playerEntity.setFlag(EntityFlag.SWIMMING, false); + playerEntity.updateBedrockMetadata(); + return; + } + toggleSwimmingPose(swimming, EntityFlag.SWIMMING); + } + + public void setCrawling(boolean crawling) { + toggleSwimmingPose(crawling, EntityFlag.CRAWLING); + } + + private void toggleSwimmingPose(boolean crawling, EntityFlag flag) { + if (crawling) { this.pose = Pose.SWIMMING; playerEntity.setBoundingBoxHeight(0.6f); } else { this.pose = Pose.STANDING; playerEntity.setBoundingBoxHeight(playerEntity.getDefinition().height()); } - playerEntity.setFlag(EntityFlag.SWIMMING, swimming); + playerEntity.setFlag(flag, crawling); playerEntity.updateBedrockMetadata(); } @@ -1423,6 +1422,12 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { this.cameraData.handleGameModeChange(currentlySpectator, newGamemode); } + public void setClientData(BedrockClientData data) { + this.clientData = data; + this.inputCache.setInputMode( + org.cloudburstmc.protocol.bedrock.data.InputMode.values()[data.getCurrentInputMode().ordinal()]); + } + /** * Convenience method to reduce amount of duplicate code. Sends ServerboundUseItemPacket. */ @@ -1671,7 +1676,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { startGamePacket.setChatRestrictionLevel(ChatRestrictionLevel.NONE); - startGamePacket.setAuthoritativeMovementMode(AuthoritativeMovementMode.CLIENT); + startGamePacket.setAuthoritativeMovementMode(AuthoritativeMovementMode.SERVER); startGamePacket.setRewindHistorySize(0); startGamePacket.setServerAuthoritativeBlockBreaking(false); @@ -1969,7 +1974,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { public void sendJavaClientSettings() { ServerboundClientInformationPacket clientSettingsPacket = new ServerboundClientInformationPacket(locale(), getRenderDistance(), ChatVisibility.FULL, true, SKIN_PARTS, - HandPreference.RIGHT_HAND, false, true); + HandPreference.RIGHT_HAND, false, true, ParticleStatus.ALL); // TODO particle status sendDownstreamPacket(clientSettingsPacket); } @@ -2136,7 +2141,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Override public @NonNull InputMode inputMode() { - return InputMode.values()[clientData.getCurrentInputMode().ordinal()]; //todo + return InputMode.values()[inputCache.getInputMode().ordinal()]; //todo } @Override diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/InputCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/InputCache.java new file mode 100644 index 000000000..f12c4d3c8 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/session/cache/InputCache.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2024 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.session.cache; + +import lombok.Getter; +import lombok.Setter; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; +import org.cloudburstmc.math.vector.Vector2f; +import org.cloudburstmc.protocol.bedrock.data.InputMode; +import org.cloudburstmc.protocol.bedrock.data.PlayerAuthInputData; +import org.cloudburstmc.protocol.bedrock.packet.PlayerAuthInputPacket; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundPlayerInputPacket; + +import java.util.Set; + +public final class InputCache { + private final GeyserSession session; + private ServerboundPlayerInputPacket inputPacket = new ServerboundPlayerInputPacket(false, false, false, false, false, false, false); + private boolean lastHorizontalCollision; + private int ticksSinceLastMovePacket; + @Getter @Setter + private int jumpingTicks; + @Getter @Setter + private float jumpScale; + @Getter @Setter + private @MonotonicNonNull InputMode inputMode; + + public InputCache(GeyserSession session) { + this.session = session; + } + + public void processInputs(PlayerAuthInputPacket packet) { + // Input is sent to the server before packet positions, as of 1.21.2 + Set bedrockInput = packet.getInputData(); + var oldInputPacket = this.inputPacket; + this.inputMode = packet.getInputMode(); + + boolean up, down, left, right; + if (this.inputMode == InputMode.MOUSE) { + up = bedrockInput.contains(PlayerAuthInputData.UP); + down = bedrockInput.contains(PlayerAuthInputData.DOWN); + left = bedrockInput.contains(PlayerAuthInputData.LEFT); + right = bedrockInput.contains(PlayerAuthInputData.RIGHT); + } else { + // The above flags don't fire TODO test console + Vector2f analogMovement = packet.getAnalogMoveVector(); + up = analogMovement.getY() > 0; + down = analogMovement.getY() < 0; + left = analogMovement.getX() > 0; + right = analogMovement.getX() < 0; + } + + // TODO when is UP_LEFT, etc. used? + this.inputPacket = this.inputPacket + .withForward(up) + .withBackward(down) + .withLeft(left) + .withRight(right) + .withJump(bedrockInput.contains(PlayerAuthInputData.JUMPING)) // Looks like this only triggers when the JUMP key input is being pressed. There's also JUMP_DOWN? + .withShift(bedrockInput.contains(PlayerAuthInputData.SNEAKING)) + .withSprint(bedrockInput.contains(PlayerAuthInputData.SPRINTING)); // SPRINTING will trigger even if the player isn't moving + + if (oldInputPacket != this.inputPacket) { // Simple equality check is fine since we're checking for an instance change. + session.sendDownstreamGamePacket(this.inputPacket); + } + } + + public boolean wasJumping() { + return this.inputPacket.isJump(); + } + + public void markPositionPacketSent() { + this.ticksSinceLastMovePacket = 0; + } + + public boolean shouldSendPositionReminder() { + // NOTE: if we implement spectating entities, DO NOT TICK THIS LOGIC THEN. + return ++this.ticksSinceLastMovePacket >= 20; + } + + public boolean lastHorizontalCollision() { + return lastHorizontalCollision; + } + + public void setLastHorizontalCollision(boolean lastHorizontalCollision) { + this.lastHorizontalCollision = lastHorizontalCollision; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/RegistryCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/RegistryCache.java index 4a4167f15..ecd293bff 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/RegistryCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/RegistryCache.java @@ -40,13 +40,16 @@ import org.cloudburstmc.protocol.bedrock.data.TrimPattern; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.entity.type.living.animal.tameable.WolfEntity; import org.geysermc.geyser.inventory.item.BannerPattern; +import org.geysermc.geyser.inventory.item.GeyserInstrument; import org.geysermc.geyser.inventory.recipe.TrimRecipe; import org.geysermc.geyser.item.enchantment.Enchantment; import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.level.JukeboxSong; import org.geysermc.geyser.level.PaintingType; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.registry.JavaRegistries; import org.geysermc.geyser.session.cache.registry.JavaRegistry; +import org.geysermc.geyser.session.cache.registry.JavaRegistryKey; import org.geysermc.geyser.session.cache.registry.RegistryEntryContext; import org.geysermc.geyser.session.cache.registry.SimpleJavaRegistry; import org.geysermc.geyser.text.ChatDecoration; @@ -80,7 +83,8 @@ public final class RegistryCache { static { register("chat_type", cache -> cache.chatTypes, ChatDecoration::readChatType); register("dimension_type", cache -> cache.dimensions, JavaDimension::read); - register("enchantment", cache -> cache.enchantments, Enchantment::read); + register(JavaRegistries.ENCHANTMENT, cache -> cache.enchantments, Enchantment::read); + register("instrument", cache -> cache.instruments, GeyserInstrument::read); register("jukebox_song", cache -> cache.jukeboxSongs, JukeboxSong::read); register("painting_variant", cache -> cache.paintings, context -> PaintingType.getByName(context.id())); register("trim_material", cache -> cache.trimMaterials, TrimRecipe::readTrimMaterial); @@ -94,8 +98,7 @@ public final class RegistryCache { Map> defaults = new HashMap<>(); // Don't create a keySet - no need to create the cached object in HashMap if we don't use it again REGISTRIES.forEach((key, $) -> { - List rawValues = tag.getCompound(key.asString()) - .getList("value", NbtType.COMPOUND); + List rawValues = tag.getCompound(key.asString()).getList("value", NbtType.COMPOUND); Map values = new HashMap<>(); for (NbtMap value : rawValues) { Key name = MinecraftKey.key(value.getString("name")); @@ -128,6 +131,7 @@ public final class RegistryCache { private final JavaRegistry bannerPatterns = new SimpleJavaRegistry<>(); private final JavaRegistry wolfVariants = new SimpleJavaRegistry<>(); + private final JavaRegistry instruments = new SimpleJavaRegistry<>(); public RegistryCache(GeyserSession session) { this.session = session; @@ -152,8 +156,27 @@ public final class RegistryCache { * @param the class that represents these entries. */ private static void register(String registry, Function> localCacheFunction, Function reader) { - Key registryKey = MinecraftKey.key(registry); - REGISTRIES.put(registryKey, (registryCache, entries) -> { + register(MinecraftKey.key(registry), localCacheFunction, reader); + } + + /** + * @param registry the Java registry resource location. + * @param localCacheFunction which local field in RegistryCache are we caching entries for this registry? + * @param reader converts the RegistryEntry NBT into a class file + * @param the class that represents these entries. + */ + private static void register(JavaRegistryKey registry, Function> localCacheFunction, Function reader) { + register(registry.registryKey(), localCacheFunction, reader); + } + + /** + * @param registry the Java registry resource location. + * @param localCacheFunction which local field in RegistryCache are we caching entries for this registry? + * @param reader converts the RegistryEntry NBT into a class file + * @param the class that represents these entries. + */ + private static void register(Key registry, Function> localCacheFunction, Function reader) { + REGISTRIES.put(registry, (registryCache, entries) -> { Map localRegistry = null; JavaRegistry localCache = localCacheFunction.apply(registryCache); // Clear each local cache every time a new registry entry is given to us @@ -172,7 +195,7 @@ public final class RegistryCache { // If the data is null, that's the server telling us we need to use our default values. if (entry.getData() == null) { if (localRegistry == null) { // Lazy initialize - localRegistry = DEFAULTS.get(registryKey); + localRegistry = DEFAULTS.get(registry); } entry = new RegistryEntry(entry.getId(), localRegistry.get(entry.getId())); } diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/TagCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/TagCache.java index f4d69dcdb..2b0f257a3 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/TagCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/TagCache.java @@ -26,116 +26,119 @@ package org.geysermc.geyser.session.cache; import it.unimi.dsi.fastutil.ints.IntArrays; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import net.kyori.adventure.key.Key; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.type.Item; -import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.session.cache.tags.BlockTag; -import org.geysermc.geyser.session.cache.tags.EnchantmentTag; -import org.geysermc.geyser.session.cache.tags.ItemTag; +import org.geysermc.geyser.session.cache.registry.JavaRegistries; +import org.geysermc.geyser.session.cache.registry.JavaRegistryKey; +import org.geysermc.geyser.session.cache.tags.GeyserHolderSet; +import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.geyser.util.MinecraftKey; -import org.geysermc.geyser.util.Ordered; import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.ClientboundUpdateTagsPacket; import javax.annotation.ParametersAreNonnullByDefault; import java.util.Arrays; +import java.util.List; import java.util.Map; -import static org.geysermc.geyser.session.cache.tags.BlockTag.ALL_BLOCK_TAGS; -import static org.geysermc.geyser.session.cache.tags.EnchantmentTag.ALL_ENCHANTMENT_TAGS; -import static org.geysermc.geyser.session.cache.tags.ItemTag.ALL_ITEM_TAGS; - /** * Manages information sent from the {@link ClientboundUpdateTagsPacket}. If that packet is not sent, all lists here - * will remain empty, matching Java Edition behavior. + * will remain empty, matching Java Edition behavior. Looking up a tag that wasn't listed in that packet will return an empty array. + * Only tags from suitable registries in {@link JavaRegistries} are stored. Read {@link JavaRegistryKey} for more information. */ @ParametersAreNonnullByDefault public final class TagCache { - private final int[][] blocks = new int[ALL_BLOCK_TAGS.size()][]; - private final int[][] items = new int[ALL_ITEM_TAGS.size()][]; - private final int[][] enchantments = new int[ALL_ENCHANTMENT_TAGS.size()][]; + private final GeyserSession session; + private final Map, int[]> tags = new Object2ObjectOpenHashMap<>(); + + public TagCache(GeyserSession session) { + this.session = session; + } public void loadPacket(GeyserSession session, ClientboundUpdateTagsPacket packet) { - Map blockTags = packet.getTags().get(MinecraftKey.key("block")); - loadTags("Block", blockTags, ALL_BLOCK_TAGS, this.blocks); - - // Hack btw + Map> allTags = packet.getTags(); GeyserLogger logger = session.getGeyser().getLogger(); - int[] convertableToMud = blockTags.get(MinecraftKey.key("convertable_to_mud")); - boolean emulatePost1_18Logic = convertableToMud != null && convertableToMud.length != 0; - session.setEmulatePost1_18Logic(emulatePost1_18Logic); - if (logger.isDebug()) { - logger.debug("Emulating post 1.18 block predication logic for " + session.bedrockUsername() + "? " + emulatePost1_18Logic); - } - Map itemTags = packet.getTags().get(MinecraftKey.key("item")); - loadTags("Item", itemTags, ALL_ITEM_TAGS, this.items); + this.tags.clear(); - // Hack btw - boolean emulatePost1_13Logic = itemTags.get(MinecraftKey.key("signs")).length > 1; - session.setEmulatePost1_13Logic(emulatePost1_13Logic); - if (logger.isDebug()) { - logger.debug("Emulating post 1.13 villager logic for " + session.bedrockUsername() + "? " + emulatePost1_13Logic); - } - - Map enchantmentTags = packet.getTags().get(MinecraftKey.key("enchantment")); - loadTags("Enchantment", enchantmentTags, ALL_ENCHANTMENT_TAGS, this.enchantments); - } - - private void loadTags(String type, @Nullable Map packetTags, Map allTags, int[][] localValues) { - if (packetTags == null) { - Arrays.fill(localValues, IntArrays.EMPTY_ARRAY); - GeyserImpl.getInstance().getLogger().debug("Not loading " + type + " tags; they do not exist here."); - return; - } - allTags.forEach((location, tag) -> { - int[] values = packetTags.get(location); - if (values != null) { - if (values.length != 0) { - localValues[tag.ordinal()] = values; - } else { - localValues[tag.ordinal()] = IntArrays.EMPTY_ARRAY; - } - } else { - localValues[tag.ordinal()] = IntArrays.EMPTY_ARRAY; - GeyserImpl.getInstance().getLogger().debug(type + " tag not found from server: " + location); + for (Key registryKey : allTags.keySet()) { + JavaRegistryKey registry = JavaRegistries.fromKey(registryKey); + if (registry == null || !registry.shouldStoreTags()) { + logger.debug("Not loading tags for registry " + registryKey + " (registry not listed in JavaRegistries, or was not suitable to load tags)"); + continue; } - }); + + Map registryTags = allTags.get(registryKey); + + if (registry == JavaRegistries.BLOCK) { + // Hack btw + int[] convertableToMud = registryTags.get(MinecraftKey.key("convertable_to_mud")); + boolean emulatePost1_18Logic = convertableToMud != null && convertableToMud.length != 0; + session.setEmulatePost1_18Logic(emulatePost1_18Logic); + if (logger.isDebug()) { + logger.debug("Emulating post 1.18 block predication logic for " + session.bedrockUsername() + "? " + emulatePost1_18Logic); + } + } else if (registry == JavaRegistries.ITEM) { + // Hack btw + boolean emulatePost1_13Logic = registryTags.get(MinecraftKey.key("signs")).length > 1; + session.setEmulatePost1_13Logic(emulatePost1_13Logic); + if (logger.isDebug()) { + logger.debug("Emulating post 1.13 villager logic for " + session.bedrockUsername() + "? " + emulatePost1_13Logic); + } + } + + loadTags(registryTags, registry, registry == JavaRegistries.ITEM); + } } - /** - * @return true if the block tag is present and contains this block mapping's Java ID. - */ - public boolean is(BlockTag tag, Block block) { - int[] values = this.blocks[tag.ordinal()]; - return contains(values, block.javaId()); + private void loadTags(Map packetTags, JavaRegistryKey registry, boolean sort) { + for (Map.Entry tag : packetTags.entrySet()) { + int[] value = tag.getValue(); + if (sort) { + // Used in RecipeBookAddTranslator + Arrays.sort(value); + } + this.tags.put(new Tag<>(registry, tag.getKey()), value); + } + } + + public boolean is(Tag tag, T object) { + return contains(getRaw(tag), tag.registry().toNetworkId(session, object)); } /** * @return true if the item tag is present and contains this item stack's Java ID. */ - public boolean is(ItemTag tag, GeyserItemStack itemStack) { + public boolean is(Tag tag, GeyserItemStack itemStack) { return is(tag, itemStack.asItem()); } /** - * @return true if the item tag is present and contains this item's Java ID. + * @return true if the specified network ID is in the given holder set. */ - public boolean is(ItemTag tag, Item item) { - int[] values = this.items[tag.ordinal()]; - return contains(values, item.javaId()); + public boolean is(GeyserHolderSet holderSet, T object) { + return contains(holderSet.resolveRaw(this), holderSet.getRegistry().toNetworkId(session, object)); } - public int[] get(ItemTag itemTag) { - return this.items[itemTag.ordinal()]; + public List get(Tag tag) { + return mapRawArray(session, getRaw(tag), tag.registry()); } - public int[] get(EnchantmentTag enchantmentTag) { - return this.enchantments[enchantmentTag.ordinal()]; + /** + * @return the network IDs in the given tag. This can be an empty list. + */ + public int[] getRaw(Tag tag) { + return this.tags.getOrDefault(tag, IntArrays.EMPTY_ARRAY); + } + + /** + * Maps a raw array of network IDs to their respective objects. + */ + public static List mapRawArray(GeyserSession session, int[] array, JavaRegistryKey registry) { + return Arrays.stream(array).mapToObj(i -> registry.fromNetworkId(session, i)).toList(); } private static boolean contains(int[] array, int i) { diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/TeleportCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/TeleportCache.java index 80139a988..7a7a5f1e2 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/TeleportCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/TeleportCache.java @@ -48,7 +48,7 @@ public class TeleportCache { /** * How many move packets the teleport can be unconfirmed for before it gets resent to the client */ - private static final int RESEND_THRESHOLD = 5; + private static final int RESEND_THRESHOLD = 20; // Make it one full second with auth input private final double x, y, z; private final float pitch, yaw; diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/WorldCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/WorldCache.java index f2198c7dc..609ac3f3b 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/WorldCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/WorldCache.java @@ -31,15 +31,18 @@ import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import lombok.Getter; import lombok.Setter; +import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.packet.SetTitlePacket; -import org.geysermc.geyser.item.type.Item; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.scoreboard.Scoreboard; import org.geysermc.geyser.scoreboard.ScoreboardUpdater.ScoreboardSession; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.ChunkUtils; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.UseCooldown; import org.geysermc.mcprotocollib.protocol.data.game.setting.Difficulty; import java.util.Iterator; @@ -72,7 +75,7 @@ public final class WorldCache { @Setter private boolean editingSignOnFront; - private final Object2IntMap activeCooldowns = new Object2IntOpenHashMap<>(2); + private final Object2IntMap activeCooldowns = new Object2IntOpenHashMap<>(2); public WorldCache(GeyserSession session) { this.session = session; @@ -204,17 +207,24 @@ public final class WorldCache { return this.activeRecords.remove(pos); } - public void setCooldown(Item item, int ticks) { + public void setCooldown(Key cooldownGroup, int ticks) { if (ticks == 0) { // As of Java 1.21 - this.activeCooldowns.removeInt(item); + this.activeCooldowns.removeInt(cooldownGroup.asString()); return; } - this.activeCooldowns.put(item, session.getTicks() + ticks); + this.activeCooldowns.put(cooldownGroup.asString(), session.getTicks() + ticks); } - public boolean hasCooldown(Item item) { - return this.activeCooldowns.containsKey(item); + public boolean hasCooldown(GeyserItemStack item) { + UseCooldown cooldown = item.getComponent(DataComponentType.USE_COOLDOWN); + String cooldownGroup; + if (cooldown != null && cooldown.cooldownGroup() != null) { + cooldownGroup = cooldown.cooldownGroup().asString(); + } else { + cooldownGroup = item.asItem().javaIdentifier(); + } + return this.activeCooldowns.containsKey(cooldownGroup); } public void tick() { @@ -222,9 +232,9 @@ public final class WorldCache { // but we don't want the cooldown field to balloon in size from overuse. if (!this.activeCooldowns.isEmpty()) { int ticks = session.getTicks(); - Iterator> it = Object2IntMaps.fastIterator(this.activeCooldowns); + Iterator> it = Object2IntMaps.fastIterator(this.activeCooldowns); while (it.hasNext()) { - Object2IntMap.Entry entry = it.next(); + Object2IntMap.Entry entry = it.next(); if (entry.getIntValue() <= ticks) { it.remove(); } diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/registry/JavaRegistries.java b/core/src/main/java/org/geysermc/geyser/session/cache/registry/JavaRegistries.java new file mode 100644 index 000000000..646b647d0 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/session/cache/registry/JavaRegistries.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2024 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.session.cache.registry; + +import net.kyori.adventure.key.Key; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.geyser.item.enchantment.Enchantment; +import org.geysermc.geyser.item.type.Item; +import org.geysermc.geyser.level.block.type.Block; +import org.geysermc.geyser.registry.BlockRegistries; +import org.geysermc.geyser.registry.ListRegistry; +import org.geysermc.geyser.registry.Registries; +import org.geysermc.geyser.session.cache.RegistryCache; +import org.geysermc.geyser.util.MinecraftKey; + +import java.util.ArrayList; +import java.util.List; + +/** + * Stores {@link JavaRegistryKey} for Java registries that are used for loading of data-driven objects, tags, or both. Read {@link JavaRegistryKey} for more information on how to use one. + */ +public class JavaRegistries { + private static final List> VALUES = new ArrayList<>(); + + public static final JavaRegistryKey BLOCK = create("block", BlockRegistries.JAVA_BLOCKS, Block::javaId); + public static final JavaRegistryKey ITEM = create("item", Registries.JAVA_ITEMS, Item::javaId); + public static final JavaRegistryKey ENCHANTMENT = create("enchantment", RegistryCache::enchantments); + + private static JavaRegistryKey create(String key, JavaRegistryKey.NetworkSerializer networkSerializer, JavaRegistryKey.NetworkDeserializer networkDeserializer) { + JavaRegistryKey registry = new JavaRegistryKey<>(MinecraftKey.key(key), networkSerializer, networkDeserializer); + VALUES.add(registry); + return registry; + } + + private static JavaRegistryKey create(String key, ListRegistry registry, RegistryNetworkMapper networkSerializer) { + return create(key, (session, object) -> networkSerializer.get(object), (session, id) -> registry.get(id)); + } + + private static JavaRegistryKey create(String key, RegistryGetter getter) { + return create(key, (session, object) -> getter.get(session.getRegistryCache()).byValue(object), (session, id) -> getter.get(session.getRegistryCache()).byId(id)); + } + + @Nullable + public static JavaRegistryKey fromKey(Key registryKey) { + for (JavaRegistryKey registry : VALUES) { + if (registry.registryKey().equals(registryKey)) { + return registry; + } + } + return null; + } + + @FunctionalInterface + interface RegistryGetter { + + JavaRegistry get(RegistryCache cache); + } + + @FunctionalInterface + interface RegistryNetworkMapper { + + int get(T object); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/registry/JavaRegistryKey.java b/core/src/main/java/org/geysermc/geyser/session/cache/registry/JavaRegistryKey.java new file mode 100644 index 000000000..369bea7a4 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/session/cache/registry/JavaRegistryKey.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2024 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.session.cache.registry; + +import net.kyori.adventure.key.Key; +import org.geysermc.geyser.session.GeyserSession; + +import javax.annotation.Nullable; + +/** + * Defines a Java registry, which can be hardcoded or data-driven. This class doesn't store registry contents itself, that is handled by {@link org.geysermc.geyser.session.cache.RegistryCache} in the case of + * data-driven registries and other classes in the case of hardcoded registries. + * + *

This class is used when, for a Java registry, data-driven objects or tags need to be loaded. Only one instance of this class should be created for each Java registry. Instances of this + * class are kept in {@link JavaRegistries}, which also has useful methods for creating instances of this class. When only using a registry to load data-driven objects, the network (de)serializer parameters + * can be null. For tag loading however, these are required, as {@link org.geysermc.geyser.session.cache.TagCache} relies on their functionality.

+ * + * @param registryKey the registry key, as it appears on Java. + * @param networkSerializer a method that converts an object in this registry to its network ID. + * @param networkDeserializer a method that converts a network ID to an object in this registry. + * @param the object type this registry holds. + */ +public record JavaRegistryKey(Key registryKey, @Nullable NetworkSerializer networkSerializer, @Nullable NetworkDeserializer networkDeserializer) { + + /** + * Converts an object in this registry to its network ID. This will fail if this registry doesn't have a network serializer. + */ + public int toNetworkId(GeyserSession session, T object) { + if (networkSerializer == null) { + throw new UnsupportedOperationException("Registry does not hava a network serializer"); + } + return networkSerializer.toNetworkId(session, object); + } + + /** + * Converts a network ID to an object in this registry. This will fail if this registry doesn't have a network deserializer. + */ + public T fromNetworkId(GeyserSession session, int networkId) { + if (networkDeserializer == null) { + throw new UnsupportedOperationException("Registry does not hava a network deserializer"); + } + return networkDeserializer.fromNetworkId(session, networkId); + } + + /** + * @return true if this registry has a network serializer and deserializer. + */ + public boolean shouldStoreTags() { + return networkSerializer != null && networkDeserializer != null; + } + + @FunctionalInterface + public interface NetworkSerializer { + + int toNetworkId(GeyserSession session, T object); + } + + @FunctionalInterface + public interface NetworkDeserializer { + + T fromNetworkId(GeyserSession session, int networkId); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/tags/BlockTag.java b/core/src/main/java/org/geysermc/geyser/session/cache/tags/BlockTag.java index 1dca7843a..6ad666780 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/tags/BlockTag.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/tags/BlockTag.java @@ -25,214 +25,203 @@ package org.geysermc.geyser.session.cache.tags; -import net.kyori.adventure.key.Key; -import org.geysermc.geyser.util.Ordered; - -import java.util.HashMap; -import java.util.Map; +import org.geysermc.geyser.level.block.type.Block; +import org.geysermc.geyser.session.cache.registry.JavaRegistries; +import org.geysermc.geyser.util.MinecraftKey; +/** + * Lists vanilla block tags. + */ @SuppressWarnings("unused") -public final class BlockTag implements Ordered { - public static final Map ALL_BLOCK_TAGS = new HashMap<>(); +public final class BlockTag { + public static final Tag WOOL = create("wool"); + public static final Tag PLANKS = create("planks"); + public static final Tag STONE_BRICKS = create("stone_bricks"); + public static final Tag WOODEN_BUTTONS = create("wooden_buttons"); + public static final Tag STONE_BUTTONS = create("stone_buttons"); + public static final Tag BUTTONS = create("buttons"); + public static final Tag WOOL_CARPETS = create("wool_carpets"); + public static final Tag WOODEN_DOORS = create("wooden_doors"); + public static final Tag MOB_INTERACTABLE_DOORS = create("mob_interactable_doors"); + public static final Tag WOODEN_STAIRS = create("wooden_stairs"); + public static final Tag WOODEN_SLABS = create("wooden_slabs"); + public static final Tag WOODEN_FENCES = create("wooden_fences"); + public static final Tag PRESSURE_PLATES = create("pressure_plates"); + public static final Tag WOODEN_PRESSURE_PLATES = create("wooden_pressure_plates"); + public static final Tag STONE_PRESSURE_PLATES = create("stone_pressure_plates"); + public static final Tag WOODEN_TRAPDOORS = create("wooden_trapdoors"); + public static final Tag DOORS = create("doors"); + public static final Tag SAPLINGS = create("saplings"); + public static final Tag LOGS_THAT_BURN = create("logs_that_burn"); + public static final Tag OVERWORLD_NATURAL_LOGS = create("overworld_natural_logs"); + public static final Tag LOGS = create("logs"); + public static final Tag DARK_OAK_LOGS = create("dark_oak_logs"); + public static final Tag OAK_LOGS = create("oak_logs"); + public static final Tag BIRCH_LOGS = create("birch_logs"); + public static final Tag ACACIA_LOGS = create("acacia_logs"); + public static final Tag CHERRY_LOGS = create("cherry_logs"); + public static final Tag JUNGLE_LOGS = create("jungle_logs"); + public static final Tag SPRUCE_LOGS = create("spruce_logs"); + public static final Tag MANGROVE_LOGS = create("mangrove_logs"); + public static final Tag CRIMSON_STEMS = create("crimson_stems"); + public static final Tag WARPED_STEMS = create("warped_stems"); + public static final Tag BAMBOO_BLOCKS = create("bamboo_blocks"); + public static final Tag WART_BLOCKS = create("wart_blocks"); + public static final Tag BANNERS = create("banners"); + public static final Tag SAND = create("sand"); + public static final Tag SMELTS_TO_GLASS = create("smelts_to_glass"); + public static final Tag STAIRS = create("stairs"); + public static final Tag SLABS = create("slabs"); + public static final Tag WALLS = create("walls"); + public static final Tag ANVIL = create("anvil"); + public static final Tag RAILS = create("rails"); + public static final Tag LEAVES = create("leaves"); + public static final Tag TRAPDOORS = create("trapdoors"); + public static final Tag SMALL_FLOWERS = create("small_flowers"); + public static final Tag BEDS = create("beds"); + public static final Tag FENCES = create("fences"); + public static final Tag TALL_FLOWERS = create("tall_flowers"); + public static final Tag FLOWERS = create("flowers"); + public static final Tag PIGLIN_REPELLENTS = create("piglin_repellents"); + public static final Tag GOLD_ORES = create("gold_ores"); + public static final Tag IRON_ORES = create("iron_ores"); + public static final Tag DIAMOND_ORES = create("diamond_ores"); + public static final Tag REDSTONE_ORES = create("redstone_ores"); + public static final Tag LAPIS_ORES = create("lapis_ores"); + public static final Tag COAL_ORES = create("coal_ores"); + public static final Tag EMERALD_ORES = create("emerald_ores"); + public static final Tag COPPER_ORES = create("copper_ores"); + public static final Tag CANDLES = create("candles"); + public static final Tag DIRT = create("dirt"); + public static final Tag TERRACOTTA = create("terracotta"); + public static final Tag BADLANDS_TERRACOTTA = create("badlands_terracotta"); + public static final Tag CONCRETE_POWDER = create("concrete_powder"); + public static final Tag COMPLETES_FIND_TREE_TUTORIAL = create("completes_find_tree_tutorial"); + public static final Tag FLOWER_POTS = create("flower_pots"); + public static final Tag ENDERMAN_HOLDABLE = create("enderman_holdable"); + public static final Tag ICE = create("ice"); + public static final Tag VALID_SPAWN = create("valid_spawn"); + public static final Tag IMPERMEABLE = create("impermeable"); + public static final Tag UNDERWATER_BONEMEALS = create("underwater_bonemeals"); + public static final Tag CORAL_BLOCKS = create("coral_blocks"); + public static final Tag WALL_CORALS = create("wall_corals"); + public static final Tag CORAL_PLANTS = create("coral_plants"); + public static final Tag CORALS = create("corals"); + public static final Tag BAMBOO_PLANTABLE_ON = create("bamboo_plantable_on"); + public static final Tag STANDING_SIGNS = create("standing_signs"); + public static final Tag WALL_SIGNS = create("wall_signs"); + public static final Tag SIGNS = create("signs"); + public static final Tag CEILING_HANGING_SIGNS = create("ceiling_hanging_signs"); + public static final Tag WALL_HANGING_SIGNS = create("wall_hanging_signs"); + public static final Tag ALL_HANGING_SIGNS = create("all_hanging_signs"); + public static final Tag ALL_SIGNS = create("all_signs"); + public static final Tag DRAGON_IMMUNE = create("dragon_immune"); + public static final Tag DRAGON_TRANSPARENT = create("dragon_transparent"); + public static final Tag WITHER_IMMUNE = create("wither_immune"); + public static final Tag WITHER_SUMMON_BASE_BLOCKS = create("wither_summon_base_blocks"); + public static final Tag BEEHIVES = create("beehives"); + public static final Tag CROPS = create("crops"); + public static final Tag BEE_GROWABLES = create("bee_growables"); + public static final Tag PORTALS = create("portals"); + public static final Tag FIRE = create("fire"); + public static final Tag NYLIUM = create("nylium"); + public static final Tag BEACON_BASE_BLOCKS = create("beacon_base_blocks"); + public static final Tag SOUL_SPEED_BLOCKS = create("soul_speed_blocks"); + public static final Tag WALL_POST_OVERRIDE = create("wall_post_override"); + public static final Tag CLIMBABLE = create("climbable"); + public static final Tag FALL_DAMAGE_RESETTING = create("fall_damage_resetting"); + public static final Tag SHULKER_BOXES = create("shulker_boxes"); + public static final Tag HOGLIN_REPELLENTS = create("hoglin_repellents"); + public static final Tag SOUL_FIRE_BASE_BLOCKS = create("soul_fire_base_blocks"); + public static final Tag STRIDER_WARM_BLOCKS = create("strider_warm_blocks"); + public static final Tag CAMPFIRES = create("campfires"); + public static final Tag GUARDED_BY_PIGLINS = create("guarded_by_piglins"); + public static final Tag PREVENT_MOB_SPAWNING_INSIDE = create("prevent_mob_spawning_inside"); + public static final Tag FENCE_GATES = create("fence_gates"); + public static final Tag UNSTABLE_BOTTOM_CENTER = create("unstable_bottom_center"); + public static final Tag MUSHROOM_GROW_BLOCK = create("mushroom_grow_block"); + public static final Tag INFINIBURN_OVERWORLD = create("infiniburn_overworld"); + public static final Tag INFINIBURN_NETHER = create("infiniburn_nether"); + public static final Tag INFINIBURN_END = create("infiniburn_end"); + public static final Tag BASE_STONE_OVERWORLD = create("base_stone_overworld"); + public static final Tag STONE_ORE_REPLACEABLES = create("stone_ore_replaceables"); + public static final Tag DEEPSLATE_ORE_REPLACEABLES = create("deepslate_ore_replaceables"); + public static final Tag BASE_STONE_NETHER = create("base_stone_nether"); + public static final Tag OVERWORLD_CARVER_REPLACEABLES = create("overworld_carver_replaceables"); + public static final Tag NETHER_CARVER_REPLACEABLES = create("nether_carver_replaceables"); + public static final Tag CANDLE_CAKES = create("candle_cakes"); + public static final Tag CAULDRONS = create("cauldrons"); + public static final Tag CRYSTAL_SOUND_BLOCKS = create("crystal_sound_blocks"); + public static final Tag INSIDE_STEP_SOUND_BLOCKS = create("inside_step_sound_blocks"); + public static final Tag COMBINATION_STEP_SOUND_BLOCKS = create("combination_step_sound_blocks"); + public static final Tag CAMEL_SAND_STEP_SOUND_BLOCKS = create("camel_sand_step_sound_blocks"); + public static final Tag OCCLUDES_VIBRATION_SIGNALS = create("occludes_vibration_signals"); + public static final Tag DAMPENS_VIBRATIONS = create("dampens_vibrations"); + public static final Tag DRIPSTONE_REPLACEABLE_BLOCKS = create("dripstone_replaceable_blocks"); + public static final Tag CAVE_VINES = create("cave_vines"); + public static final Tag MOSS_REPLACEABLE = create("moss_replaceable"); + public static final Tag LUSH_GROUND_REPLACEABLE = create("lush_ground_replaceable"); + public static final Tag AZALEA_ROOT_REPLACEABLE = create("azalea_root_replaceable"); + public static final Tag SMALL_DRIPLEAF_PLACEABLE = create("small_dripleaf_placeable"); + public static final Tag BIG_DRIPLEAF_PLACEABLE = create("big_dripleaf_placeable"); + public static final Tag SNOW = create("snow"); + public static final Tag MINEABLE_AXE = create("mineable/axe"); + public static final Tag MINEABLE_HOE = create("mineable/hoe"); + public static final Tag MINEABLE_PICKAXE = create("mineable/pickaxe"); + public static final Tag MINEABLE_SHOVEL = create("mineable/shovel"); + public static final Tag SWORD_EFFICIENT = create("sword_efficient"); + public static final Tag NEEDS_DIAMOND_TOOL = create("needs_diamond_tool"); + public static final Tag NEEDS_IRON_TOOL = create("needs_iron_tool"); + public static final Tag NEEDS_STONE_TOOL = create("needs_stone_tool"); + public static final Tag INCORRECT_FOR_NETHERITE_TOOL = create("incorrect_for_netherite_tool"); + public static final Tag INCORRECT_FOR_DIAMOND_TOOL = create("incorrect_for_diamond_tool"); + public static final Tag INCORRECT_FOR_IRON_TOOL = create("incorrect_for_iron_tool"); + public static final Tag INCORRECT_FOR_STONE_TOOL = create("incorrect_for_stone_tool"); + public static final Tag INCORRECT_FOR_GOLD_TOOL = create("incorrect_for_gold_tool"); + public static final Tag INCORRECT_FOR_WOODEN_TOOL = create("incorrect_for_wooden_tool"); + public static final Tag FEATURES_CANNOT_REPLACE = create("features_cannot_replace"); + public static final Tag LAVA_POOL_STONE_CANNOT_REPLACE = create("lava_pool_stone_cannot_replace"); + public static final Tag GEODE_INVALID_BLOCKS = create("geode_invalid_blocks"); + public static final Tag FROG_PREFER_JUMP_TO = create("frog_prefer_jump_to"); + public static final Tag SCULK_REPLACEABLE = create("sculk_replaceable"); + public static final Tag SCULK_REPLACEABLE_WORLD_GEN = create("sculk_replaceable_world_gen"); + public static final Tag ANCIENT_CITY_REPLACEABLE = create("ancient_city_replaceable"); + public static final Tag VIBRATION_RESONATORS = create("vibration_resonators"); + public static final Tag ANIMALS_SPAWNABLE_ON = create("animals_spawnable_on"); + public static final Tag ARMADILLO_SPAWNABLE_ON = create("armadillo_spawnable_on"); + public static final Tag AXOLOTLS_SPAWNABLE_ON = create("axolotls_spawnable_on"); + public static final Tag GOATS_SPAWNABLE_ON = create("goats_spawnable_on"); + public static final Tag MOOSHROOMS_SPAWNABLE_ON = create("mooshrooms_spawnable_on"); + public static final Tag PARROTS_SPAWNABLE_ON = create("parrots_spawnable_on"); + public static final Tag POLAR_BEARS_SPAWNABLE_ON_ALTERNATE = create("polar_bears_spawnable_on_alternate"); + public static final Tag RABBITS_SPAWNABLE_ON = create("rabbits_spawnable_on"); + public static final Tag FOXES_SPAWNABLE_ON = create("foxes_spawnable_on"); + public static final Tag WOLVES_SPAWNABLE_ON = create("wolves_spawnable_on"); + public static final Tag FROGS_SPAWNABLE_ON = create("frogs_spawnable_on"); + public static final Tag AZALEA_GROWS_ON = create("azalea_grows_on"); + public static final Tag CONVERTABLE_TO_MUD = create("convertable_to_mud"); + public static final Tag MANGROVE_LOGS_CAN_GROW_THROUGH = create("mangrove_logs_can_grow_through"); + public static final Tag MANGROVE_ROOTS_CAN_GROW_THROUGH = create("mangrove_roots_can_grow_through"); + public static final Tag DEAD_BUSH_MAY_PLACE_ON = create("dead_bush_may_place_on"); + public static final Tag SNAPS_GOAT_HORN = create("snaps_goat_horn"); + public static final Tag REPLACEABLE_BY_TREES = create("replaceable_by_trees"); + public static final Tag SNOW_LAYER_CANNOT_SURVIVE_ON = create("snow_layer_cannot_survive_on"); + public static final Tag SNOW_LAYER_CAN_SURVIVE_ON = create("snow_layer_can_survive_on"); + public static final Tag INVALID_SPAWN_INSIDE = create("invalid_spawn_inside"); + public static final Tag SNIFFER_DIGGABLE_BLOCK = create("sniffer_diggable_block"); + public static final Tag SNIFFER_EGG_HATCH_BOOST = create("sniffer_egg_hatch_boost"); + public static final Tag TRAIL_RUINS_REPLACEABLE = create("trail_ruins_replaceable"); + public static final Tag REPLACEABLE = create("replaceable"); + public static final Tag ENCHANTMENT_POWER_PROVIDER = create("enchantment_power_provider"); + public static final Tag ENCHANTMENT_POWER_TRANSMITTER = create("enchantment_power_transmitter"); + public static final Tag MAINTAINS_FARMLAND = create("maintains_farmland"); + public static final Tag BLOCKS_WIND_CHARGE_EXPLOSIONS = create("blocks_wind_charge_explosions"); + public static final Tag DOES_NOT_BLOCK_HOPPERS = create("does_not_block_hoppers"); + public static final Tag AIR = create("air"); - public static final BlockTag WOOL = new BlockTag("wool"); - public static final BlockTag PLANKS = new BlockTag("planks"); - public static final BlockTag STONE_BRICKS = new BlockTag("stone_bricks"); - public static final BlockTag WOODEN_BUTTONS = new BlockTag("wooden_buttons"); - public static final BlockTag STONE_BUTTONS = new BlockTag("stone_buttons"); - public static final BlockTag BUTTONS = new BlockTag("buttons"); - public static final BlockTag WOOL_CARPETS = new BlockTag("wool_carpets"); - public static final BlockTag WOODEN_DOORS = new BlockTag("wooden_doors"); - public static final BlockTag MOB_INTERACTABLE_DOORS = new BlockTag("mob_interactable_doors"); - public static final BlockTag WOODEN_STAIRS = new BlockTag("wooden_stairs"); - public static final BlockTag WOODEN_SLABS = new BlockTag("wooden_slabs"); - public static final BlockTag WOODEN_FENCES = new BlockTag("wooden_fences"); - public static final BlockTag PRESSURE_PLATES = new BlockTag("pressure_plates"); - public static final BlockTag WOODEN_PRESSURE_PLATES = new BlockTag("wooden_pressure_plates"); - public static final BlockTag STONE_PRESSURE_PLATES = new BlockTag("stone_pressure_plates"); - public static final BlockTag WOODEN_TRAPDOORS = new BlockTag("wooden_trapdoors"); - public static final BlockTag DOORS = new BlockTag("doors"); - public static final BlockTag SAPLINGS = new BlockTag("saplings"); - public static final BlockTag LOGS_THAT_BURN = new BlockTag("logs_that_burn"); - public static final BlockTag OVERWORLD_NATURAL_LOGS = new BlockTag("overworld_natural_logs"); - public static final BlockTag LOGS = new BlockTag("logs"); - public static final BlockTag DARK_OAK_LOGS = new BlockTag("dark_oak_logs"); - public static final BlockTag OAK_LOGS = new BlockTag("oak_logs"); - public static final BlockTag BIRCH_LOGS = new BlockTag("birch_logs"); - public static final BlockTag ACACIA_LOGS = new BlockTag("acacia_logs"); - public static final BlockTag CHERRY_LOGS = new BlockTag("cherry_logs"); - public static final BlockTag JUNGLE_LOGS = new BlockTag("jungle_logs"); - public static final BlockTag SPRUCE_LOGS = new BlockTag("spruce_logs"); - public static final BlockTag MANGROVE_LOGS = new BlockTag("mangrove_logs"); - public static final BlockTag CRIMSON_STEMS = new BlockTag("crimson_stems"); - public static final BlockTag WARPED_STEMS = new BlockTag("warped_stems"); - public static final BlockTag BAMBOO_BLOCKS = new BlockTag("bamboo_blocks"); - public static final BlockTag WART_BLOCKS = new BlockTag("wart_blocks"); - public static final BlockTag BANNERS = new BlockTag("banners"); - public static final BlockTag SAND = new BlockTag("sand"); - public static final BlockTag SMELTS_TO_GLASS = new BlockTag("smelts_to_glass"); - public static final BlockTag STAIRS = new BlockTag("stairs"); - public static final BlockTag SLABS = new BlockTag("slabs"); - public static final BlockTag WALLS = new BlockTag("walls"); - public static final BlockTag ANVIL = new BlockTag("anvil"); - public static final BlockTag RAILS = new BlockTag("rails"); - public static final BlockTag LEAVES = new BlockTag("leaves"); - public static final BlockTag TRAPDOORS = new BlockTag("trapdoors"); - public static final BlockTag SMALL_FLOWERS = new BlockTag("small_flowers"); - public static final BlockTag BEDS = new BlockTag("beds"); - public static final BlockTag FENCES = new BlockTag("fences"); - public static final BlockTag TALL_FLOWERS = new BlockTag("tall_flowers"); - public static final BlockTag FLOWERS = new BlockTag("flowers"); - public static final BlockTag PIGLIN_REPELLENTS = new BlockTag("piglin_repellents"); - public static final BlockTag GOLD_ORES = new BlockTag("gold_ores"); - public static final BlockTag IRON_ORES = new BlockTag("iron_ores"); - public static final BlockTag DIAMOND_ORES = new BlockTag("diamond_ores"); - public static final BlockTag REDSTONE_ORES = new BlockTag("redstone_ores"); - public static final BlockTag LAPIS_ORES = new BlockTag("lapis_ores"); - public static final BlockTag COAL_ORES = new BlockTag("coal_ores"); - public static final BlockTag EMERALD_ORES = new BlockTag("emerald_ores"); - public static final BlockTag COPPER_ORES = new BlockTag("copper_ores"); - public static final BlockTag CANDLES = new BlockTag("candles"); - public static final BlockTag DIRT = new BlockTag("dirt"); - public static final BlockTag TERRACOTTA = new BlockTag("terracotta"); - public static final BlockTag BADLANDS_TERRACOTTA = new BlockTag("badlands_terracotta"); - public static final BlockTag CONCRETE_POWDER = new BlockTag("concrete_powder"); - public static final BlockTag COMPLETES_FIND_TREE_TUTORIAL = new BlockTag("completes_find_tree_tutorial"); - public static final BlockTag FLOWER_POTS = new BlockTag("flower_pots"); - public static final BlockTag ENDERMAN_HOLDABLE = new BlockTag("enderman_holdable"); - public static final BlockTag ICE = new BlockTag("ice"); - public static final BlockTag VALID_SPAWN = new BlockTag("valid_spawn"); - public static final BlockTag IMPERMEABLE = new BlockTag("impermeable"); - public static final BlockTag UNDERWATER_BONEMEALS = new BlockTag("underwater_bonemeals"); - public static final BlockTag CORAL_BLOCKS = new BlockTag("coral_blocks"); - public static final BlockTag WALL_CORALS = new BlockTag("wall_corals"); - public static final BlockTag CORAL_PLANTS = new BlockTag("coral_plants"); - public static final BlockTag CORALS = new BlockTag("corals"); - public static final BlockTag BAMBOO_PLANTABLE_ON = new BlockTag("bamboo_plantable_on"); - public static final BlockTag STANDING_SIGNS = new BlockTag("standing_signs"); - public static final BlockTag WALL_SIGNS = new BlockTag("wall_signs"); - public static final BlockTag SIGNS = new BlockTag("signs"); - public static final BlockTag CEILING_HANGING_SIGNS = new BlockTag("ceiling_hanging_signs"); - public static final BlockTag WALL_HANGING_SIGNS = new BlockTag("wall_hanging_signs"); - public static final BlockTag ALL_HANGING_SIGNS = new BlockTag("all_hanging_signs"); - public static final BlockTag ALL_SIGNS = new BlockTag("all_signs"); - public static final BlockTag DRAGON_IMMUNE = new BlockTag("dragon_immune"); - public static final BlockTag DRAGON_TRANSPARENT = new BlockTag("dragon_transparent"); - public static final BlockTag WITHER_IMMUNE = new BlockTag("wither_immune"); - public static final BlockTag WITHER_SUMMON_BASE_BLOCKS = new BlockTag("wither_summon_base_blocks"); - public static final BlockTag BEEHIVES = new BlockTag("beehives"); - public static final BlockTag CROPS = new BlockTag("crops"); - public static final BlockTag BEE_GROWABLES = new BlockTag("bee_growables"); - public static final BlockTag PORTALS = new BlockTag("portals"); - public static final BlockTag FIRE = new BlockTag("fire"); - public static final BlockTag NYLIUM = new BlockTag("nylium"); - public static final BlockTag BEACON_BASE_BLOCKS = new BlockTag("beacon_base_blocks"); - public static final BlockTag SOUL_SPEED_BLOCKS = new BlockTag("soul_speed_blocks"); - public static final BlockTag WALL_POST_OVERRIDE = new BlockTag("wall_post_override"); - public static final BlockTag CLIMBABLE = new BlockTag("climbable"); - public static final BlockTag FALL_DAMAGE_RESETTING = new BlockTag("fall_damage_resetting"); - public static final BlockTag SHULKER_BOXES = new BlockTag("shulker_boxes"); - public static final BlockTag HOGLIN_REPELLENTS = new BlockTag("hoglin_repellents"); - public static final BlockTag SOUL_FIRE_BASE_BLOCKS = new BlockTag("soul_fire_base_blocks"); - public static final BlockTag STRIDER_WARM_BLOCKS = new BlockTag("strider_warm_blocks"); - public static final BlockTag CAMPFIRES = new BlockTag("campfires"); - public static final BlockTag GUARDED_BY_PIGLINS = new BlockTag("guarded_by_piglins"); - public static final BlockTag PREVENT_MOB_SPAWNING_INSIDE = new BlockTag("prevent_mob_spawning_inside"); - public static final BlockTag FENCE_GATES = new BlockTag("fence_gates"); - public static final BlockTag UNSTABLE_BOTTOM_CENTER = new BlockTag("unstable_bottom_center"); - public static final BlockTag MUSHROOM_GROW_BLOCK = new BlockTag("mushroom_grow_block"); - public static final BlockTag INFINIBURN_OVERWORLD = new BlockTag("infiniburn_overworld"); - public static final BlockTag INFINIBURN_NETHER = new BlockTag("infiniburn_nether"); - public static final BlockTag INFINIBURN_END = new BlockTag("infiniburn_end"); - public static final BlockTag BASE_STONE_OVERWORLD = new BlockTag("base_stone_overworld"); - public static final BlockTag STONE_ORE_REPLACEABLES = new BlockTag("stone_ore_replaceables"); - public static final BlockTag DEEPSLATE_ORE_REPLACEABLES = new BlockTag("deepslate_ore_replaceables"); - public static final BlockTag BASE_STONE_NETHER = new BlockTag("base_stone_nether"); - public static final BlockTag OVERWORLD_CARVER_REPLACEABLES = new BlockTag("overworld_carver_replaceables"); - public static final BlockTag NETHER_CARVER_REPLACEABLES = new BlockTag("nether_carver_replaceables"); - public static final BlockTag CANDLE_CAKES = new BlockTag("candle_cakes"); - public static final BlockTag CAULDRONS = new BlockTag("cauldrons"); - public static final BlockTag CRYSTAL_SOUND_BLOCKS = new BlockTag("crystal_sound_blocks"); - public static final BlockTag INSIDE_STEP_SOUND_BLOCKS = new BlockTag("inside_step_sound_blocks"); - public static final BlockTag COMBINATION_STEP_SOUND_BLOCKS = new BlockTag("combination_step_sound_blocks"); - public static final BlockTag CAMEL_SAND_STEP_SOUND_BLOCKS = new BlockTag("camel_sand_step_sound_blocks"); - public static final BlockTag OCCLUDES_VIBRATION_SIGNALS = new BlockTag("occludes_vibration_signals"); - public static final BlockTag DAMPENS_VIBRATIONS = new BlockTag("dampens_vibrations"); - public static final BlockTag DRIPSTONE_REPLACEABLE_BLOCKS = new BlockTag("dripstone_replaceable_blocks"); - public static final BlockTag CAVE_VINES = new BlockTag("cave_vines"); - public static final BlockTag MOSS_REPLACEABLE = new BlockTag("moss_replaceable"); - public static final BlockTag LUSH_GROUND_REPLACEABLE = new BlockTag("lush_ground_replaceable"); - public static final BlockTag AZALEA_ROOT_REPLACEABLE = new BlockTag("azalea_root_replaceable"); - public static final BlockTag SMALL_DRIPLEAF_PLACEABLE = new BlockTag("small_dripleaf_placeable"); - public static final BlockTag BIG_DRIPLEAF_PLACEABLE = new BlockTag("big_dripleaf_placeable"); - public static final BlockTag SNOW = new BlockTag("snow"); - public static final BlockTag MINEABLE_AXE = new BlockTag("mineable/axe"); - public static final BlockTag MINEABLE_HOE = new BlockTag("mineable/hoe"); - public static final BlockTag MINEABLE_PICKAXE = new BlockTag("mineable/pickaxe"); - public static final BlockTag MINEABLE_SHOVEL = new BlockTag("mineable/shovel"); - public static final BlockTag SWORD_EFFICIENT = new BlockTag("sword_efficient"); - public static final BlockTag NEEDS_DIAMOND_TOOL = new BlockTag("needs_diamond_tool"); - public static final BlockTag NEEDS_IRON_TOOL = new BlockTag("needs_iron_tool"); - public static final BlockTag NEEDS_STONE_TOOL = new BlockTag("needs_stone_tool"); - public static final BlockTag INCORRECT_FOR_NETHERITE_TOOL = new BlockTag("incorrect_for_netherite_tool"); - public static final BlockTag INCORRECT_FOR_DIAMOND_TOOL = new BlockTag("incorrect_for_diamond_tool"); - public static final BlockTag INCORRECT_FOR_IRON_TOOL = new BlockTag("incorrect_for_iron_tool"); - public static final BlockTag INCORRECT_FOR_STONE_TOOL = new BlockTag("incorrect_for_stone_tool"); - public static final BlockTag INCORRECT_FOR_GOLD_TOOL = new BlockTag("incorrect_for_gold_tool"); - public static final BlockTag INCORRECT_FOR_WOODEN_TOOL = new BlockTag("incorrect_for_wooden_tool"); - public static final BlockTag FEATURES_CANNOT_REPLACE = new BlockTag("features_cannot_replace"); - public static final BlockTag LAVA_POOL_STONE_CANNOT_REPLACE = new BlockTag("lava_pool_stone_cannot_replace"); - public static final BlockTag GEODE_INVALID_BLOCKS = new BlockTag("geode_invalid_blocks"); - public static final BlockTag FROG_PREFER_JUMP_TO = new BlockTag("frog_prefer_jump_to"); - public static final BlockTag SCULK_REPLACEABLE = new BlockTag("sculk_replaceable"); - public static final BlockTag SCULK_REPLACEABLE_WORLD_GEN = new BlockTag("sculk_replaceable_world_gen"); - public static final BlockTag ANCIENT_CITY_REPLACEABLE = new BlockTag("ancient_city_replaceable"); - public static final BlockTag VIBRATION_RESONATORS = new BlockTag("vibration_resonators"); - public static final BlockTag ANIMALS_SPAWNABLE_ON = new BlockTag("animals_spawnable_on"); - public static final BlockTag ARMADILLO_SPAWNABLE_ON = new BlockTag("armadillo_spawnable_on"); - public static final BlockTag AXOLOTLS_SPAWNABLE_ON = new BlockTag("axolotls_spawnable_on"); - public static final BlockTag GOATS_SPAWNABLE_ON = new BlockTag("goats_spawnable_on"); - public static final BlockTag MOOSHROOMS_SPAWNABLE_ON = new BlockTag("mooshrooms_spawnable_on"); - public static final BlockTag PARROTS_SPAWNABLE_ON = new BlockTag("parrots_spawnable_on"); - public static final BlockTag POLAR_BEARS_SPAWNABLE_ON_ALTERNATE = new BlockTag("polar_bears_spawnable_on_alternate"); - public static final BlockTag RABBITS_SPAWNABLE_ON = new BlockTag("rabbits_spawnable_on"); - public static final BlockTag FOXES_SPAWNABLE_ON = new BlockTag("foxes_spawnable_on"); - public static final BlockTag WOLVES_SPAWNABLE_ON = new BlockTag("wolves_spawnable_on"); - public static final BlockTag FROGS_SPAWNABLE_ON = new BlockTag("frogs_spawnable_on"); - public static final BlockTag AZALEA_GROWS_ON = new BlockTag("azalea_grows_on"); - public static final BlockTag CONVERTABLE_TO_MUD = new BlockTag("convertable_to_mud"); - public static final BlockTag MANGROVE_LOGS_CAN_GROW_THROUGH = new BlockTag("mangrove_logs_can_grow_through"); - public static final BlockTag MANGROVE_ROOTS_CAN_GROW_THROUGH = new BlockTag("mangrove_roots_can_grow_through"); - public static final BlockTag DEAD_BUSH_MAY_PLACE_ON = new BlockTag("dead_bush_may_place_on"); - public static final BlockTag SNAPS_GOAT_HORN = new BlockTag("snaps_goat_horn"); - public static final BlockTag REPLACEABLE_BY_TREES = new BlockTag("replaceable_by_trees"); - public static final BlockTag SNOW_LAYER_CANNOT_SURVIVE_ON = new BlockTag("snow_layer_cannot_survive_on"); - public static final BlockTag SNOW_LAYER_CAN_SURVIVE_ON = new BlockTag("snow_layer_can_survive_on"); - public static final BlockTag INVALID_SPAWN_INSIDE = new BlockTag("invalid_spawn_inside"); - public static final BlockTag SNIFFER_DIGGABLE_BLOCK = new BlockTag("sniffer_diggable_block"); - public static final BlockTag SNIFFER_EGG_HATCH_BOOST = new BlockTag("sniffer_egg_hatch_boost"); - public static final BlockTag TRAIL_RUINS_REPLACEABLE = new BlockTag("trail_ruins_replaceable"); - public static final BlockTag REPLACEABLE = new BlockTag("replaceable"); - public static final BlockTag ENCHANTMENT_POWER_PROVIDER = new BlockTag("enchantment_power_provider"); - public static final BlockTag ENCHANTMENT_POWER_TRANSMITTER = new BlockTag("enchantment_power_transmitter"); - public static final BlockTag MAINTAINS_FARMLAND = new BlockTag("maintains_farmland"); - public static final BlockTag BLOCKS_WIND_CHARGE_EXPLOSIONS = new BlockTag("blocks_wind_charge_explosions"); - public static final BlockTag DOES_NOT_BLOCK_HOPPERS = new BlockTag("does_not_block_hoppers"); - public static final BlockTag AIR = new BlockTag("air"); + private BlockTag() {} - private final int id; - - private BlockTag(String identifier) { - this.id = ALL_BLOCK_TAGS.size(); - register(identifier, this); - } - - @Override - public int ordinal() { - return id; - } - - private static void register(String name, BlockTag tag) { - ALL_BLOCK_TAGS.put(Key.key(name), tag); + private static Tag create(String name) { + return new Tag<>(JavaRegistries.BLOCK, MinecraftKey.key(name)); } } diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/tags/EnchantmentTag.java b/core/src/main/java/org/geysermc/geyser/session/cache/tags/EnchantmentTag.java index 0af690abd..1ef875642 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/tags/EnchantmentTag.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/tags/EnchantmentTag.java @@ -25,67 +25,55 @@ package org.geysermc.geyser.session.cache.tags; -import net.kyori.adventure.key.Key; +import org.geysermc.geyser.item.enchantment.Enchantment; +import org.geysermc.geyser.session.cache.registry.JavaRegistries; import org.geysermc.geyser.util.MinecraftKey; -import org.geysermc.geyser.util.Ordered; - -import java.util.HashMap; -import java.util.Map; +/** + * Lists vanilla enchantment tags. + */ @SuppressWarnings("unused") -public final class EnchantmentTag implements Ordered { - public static final Map ALL_ENCHANTMENT_TAGS = new HashMap<>(); +public final class EnchantmentTag { + public static final Tag TOOLTIP_ORDER = create("tooltip_order"); + public static final Tag EXCLUSIVE_SET_ARMOR = create("exclusive_set/armor"); + public static final Tag EXCLUSIVE_SET_BOOTS = create("exclusive_set/boots"); + public static final Tag EXCLUSIVE_SET_BOW = create("exclusive_set/bow"); + public static final Tag EXCLUSIVE_SET_CROSSBOW = create("exclusive_set/crossbow"); + public static final Tag EXCLUSIVE_SET_DAMAGE = create("exclusive_set/damage"); + public static final Tag EXCLUSIVE_SET_MINING = create("exclusive_set/mining"); + public static final Tag EXCLUSIVE_SET_RIPTIDE = create("exclusive_set/riptide"); + public static final Tag TRADEABLE = create("tradeable"); + public static final Tag DOUBLE_TRADE_PRICE = create("double_trade_price"); + public static final Tag IN_ENCHANTING_TABLE = create("in_enchanting_table"); + public static final Tag ON_MOB_SPAWN_EQUIPMENT = create("on_mob_spawn_equipment"); + public static final Tag ON_TRADED_EQUIPMENT = create("on_traded_equipment"); + public static final Tag ON_RANDOM_LOOT = create("on_random_loot"); + public static final Tag CURSE = create("curse"); + public static final Tag SMELTS_LOOT = create("smelts_loot"); + public static final Tag PREVENTS_BEE_SPAWNS_WHEN_MINING = create("prevents_bee_spawns_when_mining"); + public static final Tag PREVENTS_DECORATED_POT_SHATTERING = create("prevents_decorated_pot_shattering"); + public static final Tag PREVENTS_ICE_MELTING = create("prevents_ice_melting"); + public static final Tag PREVENTS_INFESTED_SPAWNS = create("prevents_infested_spawns"); + public static final Tag TREASURE = create("treasure"); + public static final Tag NON_TREASURE = create("non_treasure"); + public static final Tag TRADES_DESERT_COMMON = create("trades/desert_common"); + public static final Tag TRADES_JUNGLE_COMMON = create("trades/jungle_common"); + public static final Tag TRADES_PLAINS_COMMON = create("trades/plains_common"); + public static final Tag TRADES_SAVANNA_COMMON = create("trades/savanna_common"); + public static final Tag TRADES_SNOW_COMMON = create("trades/snow_common"); + public static final Tag TRADES_SWAMP_COMMON = create("trades/swamp_common"); + public static final Tag TRADES_TAIGA_COMMON = create("trades/taiga_common"); + public static final Tag TRADES_DESERT_SPECIAL = create("trades/desert_special"); + public static final Tag TRADES_JUNGLE_SPECIAL = create("trades/jungle_special"); + public static final Tag TRADES_PLAINS_SPECIAL = create("trades/plains_special"); + public static final Tag TRADES_SAVANNA_SPECIAL = create("trades/savanna_special"); + public static final Tag TRADES_SNOW_SPECIAL = create("trades/snow_special"); + public static final Tag TRADES_SWAMP_SPECIAL = create("trades/swamp_special"); + public static final Tag TRADES_TAIGA_SPECIAL = create("trades/taiga_special"); - public static final EnchantmentTag TOOLTIP_ORDER = new EnchantmentTag("tooltip_order"); - public static final EnchantmentTag EXCLUSIVE_SET_ARMOR = new EnchantmentTag("exclusive_set/armor"); - public static final EnchantmentTag EXCLUSIVE_SET_BOOTS = new EnchantmentTag("exclusive_set/boots"); - public static final EnchantmentTag EXCLUSIVE_SET_BOW = new EnchantmentTag("exclusive_set/bow"); - public static final EnchantmentTag EXCLUSIVE_SET_CROSSBOW = new EnchantmentTag("exclusive_set/crossbow"); - public static final EnchantmentTag EXCLUSIVE_SET_DAMAGE = new EnchantmentTag("exclusive_set/damage"); - public static final EnchantmentTag EXCLUSIVE_SET_MINING = new EnchantmentTag("exclusive_set/mining"); - public static final EnchantmentTag EXCLUSIVE_SET_RIPTIDE = new EnchantmentTag("exclusive_set/riptide"); - public static final EnchantmentTag TRADEABLE = new EnchantmentTag("tradeable"); - public static final EnchantmentTag DOUBLE_TRADE_PRICE = new EnchantmentTag("double_trade_price"); - public static final EnchantmentTag IN_ENCHANTING_TABLE = new EnchantmentTag("in_enchanting_table"); - public static final EnchantmentTag ON_MOB_SPAWN_EQUIPMENT = new EnchantmentTag("on_mob_spawn_equipment"); - public static final EnchantmentTag ON_TRADED_EQUIPMENT = new EnchantmentTag("on_traded_equipment"); - public static final EnchantmentTag ON_RANDOM_LOOT = new EnchantmentTag("on_random_loot"); - public static final EnchantmentTag CURSE = new EnchantmentTag("curse"); - public static final EnchantmentTag SMELTS_LOOT = new EnchantmentTag("smelts_loot"); - public static final EnchantmentTag PREVENTS_BEE_SPAWNS_WHEN_MINING = new EnchantmentTag("prevents_bee_spawns_when_mining"); - public static final EnchantmentTag PREVENTS_DECORATED_POT_SHATTERING = new EnchantmentTag("prevents_decorated_pot_shattering"); - public static final EnchantmentTag PREVENTS_ICE_MELTING = new EnchantmentTag("prevents_ice_melting"); - public static final EnchantmentTag PREVENTS_INFESTED_SPAWNS = new EnchantmentTag("prevents_infested_spawns"); - public static final EnchantmentTag TREASURE = new EnchantmentTag("treasure"); - public static final EnchantmentTag NON_TREASURE = new EnchantmentTag("non_treasure"); - public static final EnchantmentTag TRADES_DESERT_COMMON = new EnchantmentTag("trades/desert_common"); - public static final EnchantmentTag TRADES_JUNGLE_COMMON = new EnchantmentTag("trades/jungle_common"); - public static final EnchantmentTag TRADES_PLAINS_COMMON = new EnchantmentTag("trades/plains_common"); - public static final EnchantmentTag TRADES_SAVANNA_COMMON = new EnchantmentTag("trades/savanna_common"); - public static final EnchantmentTag TRADES_SNOW_COMMON = new EnchantmentTag("trades/snow_common"); - public static final EnchantmentTag TRADES_SWAMP_COMMON = new EnchantmentTag("trades/swamp_common"); - public static final EnchantmentTag TRADES_TAIGA_COMMON = new EnchantmentTag("trades/taiga_common"); - public static final EnchantmentTag TRADES_DESERT_SPECIAL = new EnchantmentTag("trades/desert_special"); - public static final EnchantmentTag TRADES_JUNGLE_SPECIAL = new EnchantmentTag("trades/jungle_special"); - public static final EnchantmentTag TRADES_PLAINS_SPECIAL = new EnchantmentTag("trades/plains_special"); - public static final EnchantmentTag TRADES_SAVANNA_SPECIAL = new EnchantmentTag("trades/savanna_special"); - public static final EnchantmentTag TRADES_SNOW_SPECIAL = new EnchantmentTag("trades/snow_special"); - public static final EnchantmentTag TRADES_SWAMP_SPECIAL = new EnchantmentTag("trades/swamp_special"); - public static final EnchantmentTag TRADES_TAIGA_SPECIAL = new EnchantmentTag("trades/taiga_special"); + private EnchantmentTag() {} - private final int id; - - private EnchantmentTag(String identifier) { - this.id = ALL_ENCHANTMENT_TAGS.size(); - register(identifier, this); - } - - @Override - public int ordinal() { - return id; - } - - private static void register(String name, EnchantmentTag tag) { - ALL_ENCHANTMENT_TAGS.put(MinecraftKey.key(name), tag); + private static Tag create(String name) { + return new Tag<>(JavaRegistries.ENCHANTMENT, MinecraftKey.key(name)); } } diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/tags/GeyserHolderSet.java b/core/src/main/java/org/geysermc/geyser/session/cache/tags/GeyserHolderSet.java new file mode 100644 index 000000000..3c6e02e53 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/session/cache/tags/GeyserHolderSet.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2024 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.session.cache.tags; + +import java.util.List; +import java.util.Objects; +import java.util.function.ToIntFunction; + +import it.unimi.dsi.fastutil.ints.IntArrays; +import lombok.Data; +import net.kyori.adventure.key.Key; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.TagCache; +import org.geysermc.geyser.session.cache.registry.JavaRegistryKey; + +/** + * Similar to vanilla Minecraft's HolderSets, stores either a tag or a list of IDs (this list can also be represented as a single ID in vanilla HolderSets). + * + *

Because HolderSets utilise tags, when loading a HolderSet, Geyser must store tags for the registry the HolderSet is for (see {@link JavaRegistryKey}).

+ * + *

Use the {@link GeyserHolderSet#readHolderSet} method to easily read a HolderSet from NBT sent by a server. To turn the HolderSet into a list of network IDs, use the {@link GeyserHolderSet#resolveRaw} method. + * To turn the HolderSet into a list of objects, use the {@link GeyserHolderSet#resolve} method.

+ */ +@Data +public final class GeyserHolderSet { + + private final JavaRegistryKey registry; + private final @Nullable Tag tag; + private final int @Nullable [] holders; + + public GeyserHolderSet(JavaRegistryKey registry, int @NonNull [] holders) { + this.registry = registry; + this.tag = null; + this.holders = holders; + } + + public GeyserHolderSet(JavaRegistryKey registry, @NonNull Tag tagId) { + this.registry = registry; + this.tag = tagId; + this.holders = null; + } + + /** + * Resolves the HolderSet, and automatically maps the network IDs to their respective object types. If the HolderSet is a list of IDs, this will be returned. If it is a tag, the tag will be resolved from the tag cache. + * + * @return the HolderSet turned into a list of objects. + */ + public List resolve(GeyserSession session) { + return TagCache.mapRawArray(session, resolveRaw(session.getTagCache()), registry); + } + + /** + * Resolves the HolderSet. If the HolderSet is a list of IDs, this will be returned. If it is a tag, the tag will be resolved from the tag cache. + * + * @return the HolderSet turned into a list of objects. + */ + public int[] resolveRaw(TagCache tagCache) { + if (holders != null) { + return holders; + } + + return tagCache.getRaw(Objects.requireNonNull(tag, "HolderSet must have a tag if it doesn't have a list of IDs")); + } + + /** + * Reads a HolderSet from an object from NBT. + * + * @param session session, only used for logging purposes. + * @param registry the registry the HolderSet contains IDs from. + * @param holderSet the HolderSet as an object from NBT. + * @param keyIdMapping a function that maps resource location IDs in the HolderSet's registry to their network IDs. + */ + public static GeyserHolderSet readHolderSet(GeyserSession session, JavaRegistryKey registry, @Nullable Object holderSet, ToIntFunction keyIdMapping) { + if (holderSet == null) { + return new GeyserHolderSet<>(registry, IntArrays.EMPTY_ARRAY); + } + + if (holderSet instanceof String stringTag) { + if (stringTag.startsWith("#")) { + // Tag + return new GeyserHolderSet<>(registry, new Tag<>(registry, Key.key(stringTag.substring(1)))); // Remove '#' at beginning that indicates tag + } else if (stringTag.isEmpty()) { + return new GeyserHolderSet<>(registry, IntArrays.EMPTY_ARRAY); + } + return new GeyserHolderSet<>(registry, new int[]{keyIdMapping.applyAsInt(Key.key(stringTag))}); + } else if (holderSet instanceof List list) { + // Assume the list is a list of strings + return new GeyserHolderSet<>(registry, list.stream().map(o -> (String) o).map(Key::key).mapToInt(keyIdMapping).toArray()); + } + session.getGeyser().getLogger().warning("Failed parsing HolderSet for registry + " + registry + "! Expected either a tag, a string ID or a list of string IDs, found " + holderSet); + return new GeyserHolderSet<>(registry, IntArrays.EMPTY_ARRAY); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/tags/ItemTag.java b/core/src/main/java/org/geysermc/geyser/session/cache/tags/ItemTag.java index a2e861dd6..4f42f146a 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/tags/ItemTag.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/tags/ItemTag.java @@ -25,178 +25,166 @@ package org.geysermc.geyser.session.cache.tags; -import net.kyori.adventure.key.Key; +import org.geysermc.geyser.item.type.Item; +import org.geysermc.geyser.session.cache.registry.JavaRegistries; import org.geysermc.geyser.util.MinecraftKey; -import org.geysermc.geyser.util.Ordered; - -import java.util.HashMap; -import java.util.Map; +/** + * Lists vanilla item tags. + */ @SuppressWarnings("unused") -public final class ItemTag implements Ordered { - public static final Map ALL_ITEM_TAGS = new HashMap<>(); +public final class ItemTag { + public static final Tag WOOL = create("wool"); + public static final Tag PLANKS = create("planks"); + public static final Tag STONE_BRICKS = create("stone_bricks"); + public static final Tag WOODEN_BUTTONS = create("wooden_buttons"); + public static final Tag STONE_BUTTONS = create("stone_buttons"); + public static final Tag BUTTONS = create("buttons"); + public static final Tag WOOL_CARPETS = create("wool_carpets"); + public static final Tag WOODEN_DOORS = create("wooden_doors"); + public static final Tag WOODEN_STAIRS = create("wooden_stairs"); + public static final Tag WOODEN_SLABS = create("wooden_slabs"); + public static final Tag WOODEN_FENCES = create("wooden_fences"); + public static final Tag FENCE_GATES = create("fence_gates"); + public static final Tag WOODEN_PRESSURE_PLATES = create("wooden_pressure_plates"); + public static final Tag WOODEN_TRAPDOORS = create("wooden_trapdoors"); + public static final Tag DOORS = create("doors"); + public static final Tag SAPLINGS = create("saplings"); + public static final Tag LOGS_THAT_BURN = create("logs_that_burn"); + public static final Tag LOGS = create("logs"); + public static final Tag DARK_OAK_LOGS = create("dark_oak_logs"); + public static final Tag OAK_LOGS = create("oak_logs"); + public static final Tag BIRCH_LOGS = create("birch_logs"); + public static final Tag ACACIA_LOGS = create("acacia_logs"); + public static final Tag CHERRY_LOGS = create("cherry_logs"); + public static final Tag JUNGLE_LOGS = create("jungle_logs"); + public static final Tag SPRUCE_LOGS = create("spruce_logs"); + public static final Tag MANGROVE_LOGS = create("mangrove_logs"); + public static final Tag CRIMSON_STEMS = create("crimson_stems"); + public static final Tag WARPED_STEMS = create("warped_stems"); + public static final Tag BAMBOO_BLOCKS = create("bamboo_blocks"); + public static final Tag WART_BLOCKS = create("wart_blocks"); + public static final Tag BANNERS = create("banners"); + public static final Tag SAND = create("sand"); + public static final Tag SMELTS_TO_GLASS = create("smelts_to_glass"); + public static final Tag STAIRS = create("stairs"); + public static final Tag SLABS = create("slabs"); + public static final Tag WALLS = create("walls"); + public static final Tag ANVIL = create("anvil"); + public static final Tag RAILS = create("rails"); + public static final Tag LEAVES = create("leaves"); + public static final Tag TRAPDOORS = create("trapdoors"); + public static final Tag SMALL_FLOWERS = create("small_flowers"); + public static final Tag BEDS = create("beds"); + public static final Tag FENCES = create("fences"); + public static final Tag TALL_FLOWERS = create("tall_flowers"); + public static final Tag FLOWERS = create("flowers"); + public static final Tag PIGLIN_REPELLENTS = create("piglin_repellents"); + public static final Tag PIGLIN_LOVED = create("piglin_loved"); + public static final Tag IGNORED_BY_PIGLIN_BABIES = create("ignored_by_piglin_babies"); + public static final Tag MEAT = create("meat"); + public static final Tag SNIFFER_FOOD = create("sniffer_food"); + public static final Tag PIGLIN_FOOD = create("piglin_food"); + public static final Tag FOX_FOOD = create("fox_food"); + public static final Tag COW_FOOD = create("cow_food"); + public static final Tag GOAT_FOOD = create("goat_food"); + public static final Tag SHEEP_FOOD = create("sheep_food"); + public static final Tag WOLF_FOOD = create("wolf_food"); + public static final Tag CAT_FOOD = create("cat_food"); + public static final Tag HORSE_FOOD = create("horse_food"); + public static final Tag HORSE_TEMPT_ITEMS = create("horse_tempt_items"); + public static final Tag CAMEL_FOOD = create("camel_food"); + public static final Tag ARMADILLO_FOOD = create("armadillo_food"); + public static final Tag BEE_FOOD = create("bee_food"); + public static final Tag CHICKEN_FOOD = create("chicken_food"); + public static final Tag FROG_FOOD = create("frog_food"); + public static final Tag HOGLIN_FOOD = create("hoglin_food"); + public static final Tag LLAMA_FOOD = create("llama_food"); + public static final Tag LLAMA_TEMPT_ITEMS = create("llama_tempt_items"); + public static final Tag OCELOT_FOOD = create("ocelot_food"); + public static final Tag PANDA_FOOD = create("panda_food"); + public static final Tag PIG_FOOD = create("pig_food"); + public static final Tag RABBIT_FOOD = create("rabbit_food"); + public static final Tag STRIDER_FOOD = create("strider_food"); + public static final Tag STRIDER_TEMPT_ITEMS = create("strider_tempt_items"); + public static final Tag TURTLE_FOOD = create("turtle_food"); + public static final Tag PARROT_FOOD = create("parrot_food"); + public static final Tag PARROT_POISONOUS_FOOD = create("parrot_poisonous_food"); + public static final Tag AXOLOTL_FOOD = create("axolotl_food"); + public static final Tag GOLD_ORES = create("gold_ores"); + public static final Tag IRON_ORES = create("iron_ores"); + public static final Tag DIAMOND_ORES = create("diamond_ores"); + public static final Tag REDSTONE_ORES = create("redstone_ores"); + public static final Tag LAPIS_ORES = create("lapis_ores"); + public static final Tag COAL_ORES = create("coal_ores"); + public static final Tag EMERALD_ORES = create("emerald_ores"); + public static final Tag COPPER_ORES = create("copper_ores"); + public static final Tag NON_FLAMMABLE_WOOD = create("non_flammable_wood"); + public static final Tag SOUL_FIRE_BASE_BLOCKS = create("soul_fire_base_blocks"); + public static final Tag CANDLES = create("candles"); + public static final Tag DIRT = create("dirt"); + public static final Tag TERRACOTTA = create("terracotta"); + public static final Tag COMPLETES_FIND_TREE_TUTORIAL = create("completes_find_tree_tutorial"); + public static final Tag BOATS = create("boats"); + public static final Tag CHEST_BOATS = create("chest_boats"); + public static final Tag FISHES = create("fishes"); + public static final Tag SIGNS = create("signs"); + public static final Tag CREEPER_DROP_MUSIC_DISCS = create("creeper_drop_music_discs"); + public static final Tag COALS = create("coals"); + public static final Tag ARROWS = create("arrows"); + public static final Tag LECTERN_BOOKS = create("lectern_books"); + public static final Tag BOOKSHELF_BOOKS = create("bookshelf_books"); + public static final Tag BEACON_PAYMENT_ITEMS = create("beacon_payment_items"); + public static final Tag STONE_TOOL_MATERIALS = create("stone_tool_materials"); + public static final Tag STONE_CRAFTING_MATERIALS = create("stone_crafting_materials"); + public static final Tag FREEZE_IMMUNE_WEARABLES = create("freeze_immune_wearables"); + public static final Tag DAMPENS_VIBRATIONS = create("dampens_vibrations"); + public static final Tag CLUSTER_MAX_HARVESTABLES = create("cluster_max_harvestables"); + public static final Tag COMPASSES = create("compasses"); + public static final Tag HANGING_SIGNS = create("hanging_signs"); + public static final Tag CREEPER_IGNITERS = create("creeper_igniters"); + public static final Tag NOTEBLOCK_TOP_INSTRUMENTS = create("noteblock_top_instruments"); + public static final Tag FOOT_ARMOR = create("foot_armor"); + public static final Tag LEG_ARMOR = create("leg_armor"); + public static final Tag CHEST_ARMOR = create("chest_armor"); + public static final Tag HEAD_ARMOR = create("head_armor"); + public static final Tag SKULLS = create("skulls"); + public static final Tag TRIMMABLE_ARMOR = create("trimmable_armor"); + public static final Tag TRIM_MATERIALS = create("trim_materials"); + public static final Tag TRIM_TEMPLATES = create("trim_templates"); + public static final Tag DECORATED_POT_SHERDS = create("decorated_pot_sherds"); + public static final Tag DECORATED_POT_INGREDIENTS = create("decorated_pot_ingredients"); + public static final Tag SWORDS = create("swords"); + public static final Tag AXES = create("axes"); + public static final Tag HOES = create("hoes"); + public static final Tag PICKAXES = create("pickaxes"); + public static final Tag SHOVELS = create("shovels"); + public static final Tag BREAKS_DECORATED_POTS = create("breaks_decorated_pots"); + public static final Tag VILLAGER_PLANTABLE_SEEDS = create("villager_plantable_seeds"); + public static final Tag DYEABLE = create("dyeable"); + public static final Tag ENCHANTABLE_FOOT_ARMOR = create("enchantable/foot_armor"); + public static final Tag ENCHANTABLE_LEG_ARMOR = create("enchantable/leg_armor"); + public static final Tag ENCHANTABLE_CHEST_ARMOR = create("enchantable/chest_armor"); + public static final Tag ENCHANTABLE_HEAD_ARMOR = create("enchantable/head_armor"); + public static final Tag ENCHANTABLE_ARMOR = create("enchantable/armor"); + public static final Tag ENCHANTABLE_SWORD = create("enchantable/sword"); + public static final Tag ENCHANTABLE_FIRE_ASPECT = create("enchantable/fire_aspect"); + public static final Tag ENCHANTABLE_SHARP_WEAPON = create("enchantable/sharp_weapon"); + public static final Tag ENCHANTABLE_WEAPON = create("enchantable/weapon"); + public static final Tag ENCHANTABLE_MINING = create("enchantable/mining"); + public static final Tag ENCHANTABLE_MINING_LOOT = create("enchantable/mining_loot"); + public static final Tag ENCHANTABLE_FISHING = create("enchantable/fishing"); + public static final Tag ENCHANTABLE_TRIDENT = create("enchantable/trident"); + public static final Tag ENCHANTABLE_DURABILITY = create("enchantable/durability"); + public static final Tag ENCHANTABLE_BOW = create("enchantable/bow"); + public static final Tag ENCHANTABLE_EQUIPPABLE = create("enchantable/equippable"); + public static final Tag ENCHANTABLE_CROSSBOW = create("enchantable/crossbow"); + public static final Tag ENCHANTABLE_VANISHING = create("enchantable/vanishing"); + public static final Tag ENCHANTABLE_MACE = create("enchantable/mace"); - public static final ItemTag WOOL = new ItemTag("wool"); - public static final ItemTag PLANKS = new ItemTag("planks"); - public static final ItemTag STONE_BRICKS = new ItemTag("stone_bricks"); - public static final ItemTag WOODEN_BUTTONS = new ItemTag("wooden_buttons"); - public static final ItemTag STONE_BUTTONS = new ItemTag("stone_buttons"); - public static final ItemTag BUTTONS = new ItemTag("buttons"); - public static final ItemTag WOOL_CARPETS = new ItemTag("wool_carpets"); - public static final ItemTag WOODEN_DOORS = new ItemTag("wooden_doors"); - public static final ItemTag WOODEN_STAIRS = new ItemTag("wooden_stairs"); - public static final ItemTag WOODEN_SLABS = new ItemTag("wooden_slabs"); - public static final ItemTag WOODEN_FENCES = new ItemTag("wooden_fences"); - public static final ItemTag FENCE_GATES = new ItemTag("fence_gates"); - public static final ItemTag WOODEN_PRESSURE_PLATES = new ItemTag("wooden_pressure_plates"); - public static final ItemTag WOODEN_TRAPDOORS = new ItemTag("wooden_trapdoors"); - public static final ItemTag DOORS = new ItemTag("doors"); - public static final ItemTag SAPLINGS = new ItemTag("saplings"); - public static final ItemTag LOGS_THAT_BURN = new ItemTag("logs_that_burn"); - public static final ItemTag LOGS = new ItemTag("logs"); - public static final ItemTag DARK_OAK_LOGS = new ItemTag("dark_oak_logs"); - public static final ItemTag OAK_LOGS = new ItemTag("oak_logs"); - public static final ItemTag BIRCH_LOGS = new ItemTag("birch_logs"); - public static final ItemTag ACACIA_LOGS = new ItemTag("acacia_logs"); - public static final ItemTag CHERRY_LOGS = new ItemTag("cherry_logs"); - public static final ItemTag JUNGLE_LOGS = new ItemTag("jungle_logs"); - public static final ItemTag SPRUCE_LOGS = new ItemTag("spruce_logs"); - public static final ItemTag MANGROVE_LOGS = new ItemTag("mangrove_logs"); - public static final ItemTag CRIMSON_STEMS = new ItemTag("crimson_stems"); - public static final ItemTag WARPED_STEMS = new ItemTag("warped_stems"); - public static final ItemTag BAMBOO_BLOCKS = new ItemTag("bamboo_blocks"); - public static final ItemTag WART_BLOCKS = new ItemTag("wart_blocks"); - public static final ItemTag BANNERS = new ItemTag("banners"); - public static final ItemTag SAND = new ItemTag("sand"); - public static final ItemTag SMELTS_TO_GLASS = new ItemTag("smelts_to_glass"); - public static final ItemTag STAIRS = new ItemTag("stairs"); - public static final ItemTag SLABS = new ItemTag("slabs"); - public static final ItemTag WALLS = new ItemTag("walls"); - public static final ItemTag ANVIL = new ItemTag("anvil"); - public static final ItemTag RAILS = new ItemTag("rails"); - public static final ItemTag LEAVES = new ItemTag("leaves"); - public static final ItemTag TRAPDOORS = new ItemTag("trapdoors"); - public static final ItemTag SMALL_FLOWERS = new ItemTag("small_flowers"); - public static final ItemTag BEDS = new ItemTag("beds"); - public static final ItemTag FENCES = new ItemTag("fences"); - public static final ItemTag TALL_FLOWERS = new ItemTag("tall_flowers"); - public static final ItemTag FLOWERS = new ItemTag("flowers"); - public static final ItemTag PIGLIN_REPELLENTS = new ItemTag("piglin_repellents"); - public static final ItemTag PIGLIN_LOVED = new ItemTag("piglin_loved"); - public static final ItemTag IGNORED_BY_PIGLIN_BABIES = new ItemTag("ignored_by_piglin_babies"); - public static final ItemTag MEAT = new ItemTag("meat"); - public static final ItemTag SNIFFER_FOOD = new ItemTag("sniffer_food"); - public static final ItemTag PIGLIN_FOOD = new ItemTag("piglin_food"); - public static final ItemTag FOX_FOOD = new ItemTag("fox_food"); - public static final ItemTag COW_FOOD = new ItemTag("cow_food"); - public static final ItemTag GOAT_FOOD = new ItemTag("goat_food"); - public static final ItemTag SHEEP_FOOD = new ItemTag("sheep_food"); - public static final ItemTag WOLF_FOOD = new ItemTag("wolf_food"); - public static final ItemTag CAT_FOOD = new ItemTag("cat_food"); - public static final ItemTag HORSE_FOOD = new ItemTag("horse_food"); - public static final ItemTag HORSE_TEMPT_ITEMS = new ItemTag("horse_tempt_items"); - public static final ItemTag CAMEL_FOOD = new ItemTag("camel_food"); - public static final ItemTag ARMADILLO_FOOD = new ItemTag("armadillo_food"); - public static final ItemTag BEE_FOOD = new ItemTag("bee_food"); - public static final ItemTag CHICKEN_FOOD = new ItemTag("chicken_food"); - public static final ItemTag FROG_FOOD = new ItemTag("frog_food"); - public static final ItemTag HOGLIN_FOOD = new ItemTag("hoglin_food"); - public static final ItemTag LLAMA_FOOD = new ItemTag("llama_food"); - public static final ItemTag LLAMA_TEMPT_ITEMS = new ItemTag("llama_tempt_items"); - public static final ItemTag OCELOT_FOOD = new ItemTag("ocelot_food"); - public static final ItemTag PANDA_FOOD = new ItemTag("panda_food"); - public static final ItemTag PIG_FOOD = new ItemTag("pig_food"); - public static final ItemTag RABBIT_FOOD = new ItemTag("rabbit_food"); - public static final ItemTag STRIDER_FOOD = new ItemTag("strider_food"); - public static final ItemTag STRIDER_TEMPT_ITEMS = new ItemTag("strider_tempt_items"); - public static final ItemTag TURTLE_FOOD = new ItemTag("turtle_food"); - public static final ItemTag PARROT_FOOD = new ItemTag("parrot_food"); - public static final ItemTag PARROT_POISONOUS_FOOD = new ItemTag("parrot_poisonous_food"); - public static final ItemTag AXOLOTL_FOOD = new ItemTag("axolotl_food"); - public static final ItemTag GOLD_ORES = new ItemTag("gold_ores"); - public static final ItemTag IRON_ORES = new ItemTag("iron_ores"); - public static final ItemTag DIAMOND_ORES = new ItemTag("diamond_ores"); - public static final ItemTag REDSTONE_ORES = new ItemTag("redstone_ores"); - public static final ItemTag LAPIS_ORES = new ItemTag("lapis_ores"); - public static final ItemTag COAL_ORES = new ItemTag("coal_ores"); - public static final ItemTag EMERALD_ORES = new ItemTag("emerald_ores"); - public static final ItemTag COPPER_ORES = new ItemTag("copper_ores"); - public static final ItemTag NON_FLAMMABLE_WOOD = new ItemTag("non_flammable_wood"); - public static final ItemTag SOUL_FIRE_BASE_BLOCKS = new ItemTag("soul_fire_base_blocks"); - public static final ItemTag CANDLES = new ItemTag("candles"); - public static final ItemTag DIRT = new ItemTag("dirt"); - public static final ItemTag TERRACOTTA = new ItemTag("terracotta"); - public static final ItemTag COMPLETES_FIND_TREE_TUTORIAL = new ItemTag("completes_find_tree_tutorial"); - public static final ItemTag BOATS = new ItemTag("boats"); - public static final ItemTag CHEST_BOATS = new ItemTag("chest_boats"); - public static final ItemTag FISHES = new ItemTag("fishes"); - public static final ItemTag SIGNS = new ItemTag("signs"); - public static final ItemTag CREEPER_DROP_MUSIC_DISCS = new ItemTag("creeper_drop_music_discs"); - public static final ItemTag COALS = new ItemTag("coals"); - public static final ItemTag ARROWS = new ItemTag("arrows"); - public static final ItemTag LECTERN_BOOKS = new ItemTag("lectern_books"); - public static final ItemTag BOOKSHELF_BOOKS = new ItemTag("bookshelf_books"); - public static final ItemTag BEACON_PAYMENT_ITEMS = new ItemTag("beacon_payment_items"); - public static final ItemTag STONE_TOOL_MATERIALS = new ItemTag("stone_tool_materials"); - public static final ItemTag STONE_CRAFTING_MATERIALS = new ItemTag("stone_crafting_materials"); - public static final ItemTag FREEZE_IMMUNE_WEARABLES = new ItemTag("freeze_immune_wearables"); - public static final ItemTag DAMPENS_VIBRATIONS = new ItemTag("dampens_vibrations"); - public static final ItemTag CLUSTER_MAX_HARVESTABLES = new ItemTag("cluster_max_harvestables"); - public static final ItemTag COMPASSES = new ItemTag("compasses"); - public static final ItemTag HANGING_SIGNS = new ItemTag("hanging_signs"); - public static final ItemTag CREEPER_IGNITERS = new ItemTag("creeper_igniters"); - public static final ItemTag NOTEBLOCK_TOP_INSTRUMENTS = new ItemTag("noteblock_top_instruments"); - public static final ItemTag FOOT_ARMOR = new ItemTag("foot_armor"); - public static final ItemTag LEG_ARMOR = new ItemTag("leg_armor"); - public static final ItemTag CHEST_ARMOR = new ItemTag("chest_armor"); - public static final ItemTag HEAD_ARMOR = new ItemTag("head_armor"); - public static final ItemTag SKULLS = new ItemTag("skulls"); - public static final ItemTag TRIMMABLE_ARMOR = new ItemTag("trimmable_armor"); - public static final ItemTag TRIM_MATERIALS = new ItemTag("trim_materials"); - public static final ItemTag TRIM_TEMPLATES = new ItemTag("trim_templates"); - public static final ItemTag DECORATED_POT_SHERDS = new ItemTag("decorated_pot_sherds"); - public static final ItemTag DECORATED_POT_INGREDIENTS = new ItemTag("decorated_pot_ingredients"); - public static final ItemTag SWORDS = new ItemTag("swords"); - public static final ItemTag AXES = new ItemTag("axes"); - public static final ItemTag HOES = new ItemTag("hoes"); - public static final ItemTag PICKAXES = new ItemTag("pickaxes"); - public static final ItemTag SHOVELS = new ItemTag("shovels"); - public static final ItemTag BREAKS_DECORATED_POTS = new ItemTag("breaks_decorated_pots"); - public static final ItemTag VILLAGER_PLANTABLE_SEEDS = new ItemTag("villager_plantable_seeds"); - public static final ItemTag DYEABLE = new ItemTag("dyeable"); - public static final ItemTag ENCHANTABLE_FOOT_ARMOR = new ItemTag("enchantable/foot_armor"); - public static final ItemTag ENCHANTABLE_LEG_ARMOR = new ItemTag("enchantable/leg_armor"); - public static final ItemTag ENCHANTABLE_CHEST_ARMOR = new ItemTag("enchantable/chest_armor"); - public static final ItemTag ENCHANTABLE_HEAD_ARMOR = new ItemTag("enchantable/head_armor"); - public static final ItemTag ENCHANTABLE_ARMOR = new ItemTag("enchantable/armor"); - public static final ItemTag ENCHANTABLE_SWORD = new ItemTag("enchantable/sword"); - public static final ItemTag ENCHANTABLE_FIRE_ASPECT = new ItemTag("enchantable/fire_aspect"); - public static final ItemTag ENCHANTABLE_SHARP_WEAPON = new ItemTag("enchantable/sharp_weapon"); - public static final ItemTag ENCHANTABLE_WEAPON = new ItemTag("enchantable/weapon"); - public static final ItemTag ENCHANTABLE_MINING = new ItemTag("enchantable/mining"); - public static final ItemTag ENCHANTABLE_MINING_LOOT = new ItemTag("enchantable/mining_loot"); - public static final ItemTag ENCHANTABLE_FISHING = new ItemTag("enchantable/fishing"); - public static final ItemTag ENCHANTABLE_TRIDENT = new ItemTag("enchantable/trident"); - public static final ItemTag ENCHANTABLE_DURABILITY = new ItemTag("enchantable/durability"); - public static final ItemTag ENCHANTABLE_BOW = new ItemTag("enchantable/bow"); - public static final ItemTag ENCHANTABLE_EQUIPPABLE = new ItemTag("enchantable/equippable"); - public static final ItemTag ENCHANTABLE_CROSSBOW = new ItemTag("enchantable/crossbow"); - public static final ItemTag ENCHANTABLE_VANISHING = new ItemTag("enchantable/vanishing"); - public static final ItemTag ENCHANTABLE_MACE = new ItemTag("enchantable/mace"); + private ItemTag() {} - private final int id; - - private ItemTag(String identifier) { - this.id = ALL_ITEM_TAGS.size(); - register(identifier, this); - } - - @Override - public int ordinal() { - return id; - } - - private static void register(String name, ItemTag tag) { - ALL_ITEM_TAGS.put(MinecraftKey.key(name), tag); + private static Tag create(String name) { + return new Tag<>(JavaRegistries.ITEM, MinecraftKey.key(name)); } } diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/tags/Tag.java b/core/src/main/java/org/geysermc/geyser/session/cache/tags/Tag.java new file mode 100644 index 000000000..276e30b9f --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/session/cache/tags/Tag.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.session.cache.tags; + +import net.kyori.adventure.key.Key; +import org.geysermc.geyser.session.cache.registry.JavaRegistryKey; + +/** + * A tag in any of the registries that tags are loaded for by Geyser. + */ +public record Tag(JavaRegistryKey registry, Key tag) { +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java index 3338d2e52..15c19c542 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java @@ -25,21 +25,40 @@ package org.geysermc.geyser.translator.inventory; -import it.unimi.dsi.fastutil.ints.*; +import it.unimi.dsi.fastutil.ints.Int2IntMap; +import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntIterator; +import it.unimi.dsi.fastutil.ints.IntLinkedOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; +import it.unimi.dsi.fastutil.ints.IntSortedSet; import lombok.AllArgsConstructor; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerSlotType; import org.cloudburstmc.protocol.bedrock.data.inventory.FullContainerName; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequest; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.ItemStackRequestSlotData; -import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.*; +import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.AutoCraftRecipeAction; +import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.ConsumeAction; +import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.CraftResultsDeprecatedAction; +import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.DropAction; +import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.ItemStackRequestAction; +import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.SwapAction; +import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.request.action.TransferItemStackRequestAction; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponse; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponseContainer; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponseSlot; import org.cloudburstmc.protocol.bedrock.data.inventory.itemstack.response.ItemStackResponseStatus; import org.cloudburstmc.protocol.bedrock.packet.ItemStackResponsePacket; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.inventory.*; +import org.geysermc.geyser.inventory.BedrockContainerSlot; +import org.geysermc.geyser.inventory.CartographyContainer; +import org.geysermc.geyser.inventory.GeyserItemStack; +import org.geysermc.geyser.inventory.Inventory; +import org.geysermc.geyser.inventory.PlayerInventory; +import org.geysermc.geyser.inventory.SlotType; import org.geysermc.geyser.inventory.click.Click; import org.geysermc.geyser.inventory.click.ClickPlan; import org.geysermc.geyser.inventory.recipe.GeyserRecipe; @@ -56,12 +75,17 @@ import org.geysermc.geyser.translator.inventory.furnace.SmokerInventoryTranslato import org.geysermc.geyser.util.InventoryUtils; import org.geysermc.geyser.util.ItemUtils; import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType; -import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; -import org.geysermc.mcprotocollib.protocol.data.game.recipe.Ingredient; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.EmptySlotDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.SlotDisplay; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; @AllArgsConstructor public abstract class InventoryTranslator { @@ -642,8 +666,8 @@ public abstract class InventoryTranslator { } int gridDimensions = gridSize == 4 ? 2 : 3; - Ingredient[] ingredients = new Ingredient[0]; - ItemStack output = null; + List ingredients = Collections.emptyList(); + SlotDisplay output = null; int recipeWidth = 0; int ingRemaining = 0; int ingredientIndex = -1; @@ -697,7 +721,7 @@ public abstract class InventoryTranslator { ingredients = shapelessRecipe.ingredients(); recipeWidth = gridDimensions; output = shapelessRecipe.result(); - if (ingredients.length > gridSize) { + if (ingredients.size() > gridSize) { return rejectRequest(request); } } @@ -728,8 +752,8 @@ public abstract class InventoryTranslator { craftState = CraftState.INGREDIENTS; if (ingRemaining == 0) { - while (++ingredientIndex < ingredients.length) { - if (ingredients[ingredientIndex].getOptions().length != 0) { + while (++ingredientIndex < ingredients.size()) { + if (!(ingredients.get(ingredientIndex) instanceof EmptySlotDisplay)) { // TODO I guess can technically other options be empty? ingRemaining = timesCrafted; break; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/SmithingInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/SmithingInventoryTranslator.java index c68347fd3..dbe24230a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/SmithingInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/SmithingInventoryTranslator.java @@ -33,6 +33,11 @@ import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; import org.geysermc.geyser.level.block.Blocks; public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslator { + public static final int TEMPLATE = 0; + public static final int INPUT = 1; + public static final int MATERIAL = 2; + public static final int OUTPUT = 3; + public SmithingInventoryTranslator() { super(4, Blocks.SMITHING_TABLE, ContainerType.SMITHING_TABLE, UIInventoryUpdater.INSTANCE); } @@ -40,10 +45,10 @@ public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslato @Override public int bedrockSlotToJava(ItemStackRequestSlotData slotInfoData) { return switch (slotInfoData.getContainer()) { - case SMITHING_TABLE_TEMPLATE -> 0; - case SMITHING_TABLE_INPUT -> 1; - case SMITHING_TABLE_MATERIAL -> 2; - case SMITHING_TABLE_RESULT, CREATED_OUTPUT -> 3; + case SMITHING_TABLE_TEMPLATE -> TEMPLATE; + case SMITHING_TABLE_INPUT -> INPUT; + case SMITHING_TABLE_MATERIAL -> MATERIAL; + case SMITHING_TABLE_RESULT, CREATED_OUTPUT -> OUTPUT; default -> super.bedrockSlotToJava(slotInfoData); }; } @@ -51,10 +56,10 @@ public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslato @Override public BedrockContainerSlot javaSlotToBedrockContainer(int slot) { return switch (slot) { - case 0 -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_TEMPLATE, 53); - case 1 -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_INPUT, 51); - case 2 -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_MATERIAL, 52); - case 3 -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_RESULT, 50); + case TEMPLATE -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_TEMPLATE, 53); + case INPUT -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_INPUT, 51); + case MATERIAL -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_MATERIAL, 52); + case OUTPUT -> new BedrockContainerSlot(ContainerSlotType.SMITHING_TABLE_RESULT, 50); default -> super.javaSlotToBedrockContainer(slot); }; } @@ -62,10 +67,10 @@ public class SmithingInventoryTranslator extends AbstractBlockInventoryTranslato @Override public int javaSlotToBedrock(int slot) { return switch (slot) { - case 0 -> 53; - case 1 -> 51; - case 2 -> 52; - case 3 -> 50; + case TEMPLATE -> 53; + case INPUT -> 51; + case MATERIAL -> 52; + case OUTPUT -> 50; default -> super.javaSlotToBedrock(slot); }; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/item/ItemTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/item/ItemTranslator.java index 163eef20b..3cfd00233 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/item/ItemTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/item/ItemTranslator.java @@ -108,7 +108,7 @@ public final class ItemTranslator { ItemMapping bedrockItem = session.getItemMappings().getMapping(data); Item javaItem = bedrockItem.getJavaItem(); - GeyserItemStack itemStack = javaItem.translateToJava(data, bedrockItem, session.getItemMappings()); + GeyserItemStack itemStack = javaItem.translateToJava(session, data, bedrockItem, session.getItemMappings()); NbtMap nbt = data.getTag(); if (nbt != null && !nbt.isEmpty()) { @@ -198,7 +198,7 @@ public final class ItemTranslator { nbtMapBuilder.putIfAbsent("ench", NbtList.EMPTY); } - ItemData.Builder builder = javaItem.translateToBedrock(count, components, bedrockItem, session.getItemMappings()); + ItemData.Builder builder = javaItem.translateToBedrock(session, count, components, bedrockItem, session.getItemMappings()); // Finalize the Bedrock NBT builder.tag(nbtBuilder.build()); if (bedrockItem.isBlock()) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockAnimateTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockAnimateTranslator.java index 79e013246..5f3b9662f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockAnimateTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockAnimateTranslator.java @@ -25,13 +25,12 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundPaddleBoatPacket; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundSwingPacket; import org.cloudburstmc.protocol.bedrock.packet.AnimatePacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundSwingPacket; import java.util.concurrent.TimeUnit; @@ -45,45 +44,31 @@ public class BedrockAnimateTranslator extends PacketTranslator { return; } - switch (packet.getAction()) { - case SWING_ARM -> { - session.armSwingPending(); - // Delay so entity damage can be processed first - session.scheduleInEventLoop(() -> { - if (session.getArmAnimationTicks() != 0) { - // So, generally, a Java player can only do one *thing* at a time. - // If a player right-clicks, for example, then there's probably only one action associated with - // that right-click that will send a swing. - // The only exception I can think of to this, *maybe*, is a player dropping items - // Bedrock is a little funkier than this - it can send several arm animation packets in the - // same tick, notably with high levels of haste applied. - // Packet limiters do not like this and can crash the player. - // If arm animation ticks is 0, then we just sent an arm swing packet this tick. - // See https://github.com/GeyserMC/Geyser/issues/2875 - // This behavior was last touched on with ViaVersion 4.5.1 (with its packet limiter), Java 1.16.5, - // and Bedrock 1.19.51. - // Note for the future: we should probably largely ignore this packet and instead replicate - // all actions on our end, and send swings where needed. - session.sendDownstreamGamePacket(new ServerboundSwingPacket(Hand.MAIN_HAND)); - session.activateArmAnimationTicking(); - } - }, - 25, - TimeUnit.MILLISECONDS - ); - } - // These two might need to be flipped, but my recommendation is getting moving working first - case ROW_LEFT -> { - // Packet value is a float of how long one has been rowing, so we convert that into a boolean - session.setSteeringLeft(packet.getRowingTime() > 0.0); - ServerboundPaddleBoatPacket steerLeftPacket = new ServerboundPaddleBoatPacket(session.isSteeringLeft(), session.isSteeringRight()); - session.sendDownstreamGamePacket(steerLeftPacket); - } - case ROW_RIGHT -> { - session.setSteeringRight(packet.getRowingTime() > 0.0); - ServerboundPaddleBoatPacket steerRightPacket = new ServerboundPaddleBoatPacket(session.isSteeringLeft(), session.isSteeringRight()); - session.sendDownstreamGamePacket(steerRightPacket); - } + if (packet.getAction() == AnimatePacket.Action.SWING_ARM) { + session.armSwingPending(); + // Delay so entity damage can be processed first + session.scheduleInEventLoop(() -> { + if (session.getArmAnimationTicks() != 0) { + // So, generally, a Java player can only do one *thing* at a time. + // If a player right-clicks, for example, then there's probably only one action associated with + // that right-click that will send a swing. + // The only exception I can think of to this, *maybe*, is a player dropping items + // Bedrock is a little funkier than this - it can send several arm animation packets in the + // same tick, notably with high levels of haste applied. + // Packet limiters do not like this and can crash the player. + // If arm animation ticks is 0, then we just sent an arm swing packet this tick. + // See https://github.com/GeyserMC/Geyser/issues/2875 + // This behavior was last touched on with ViaVersion 4.5.1 (with its packet limiter), Java 1.16.5, + // and Bedrock 1.19.51. + // Note for the future: we should probably largely ignore this packet and instead replicate + // all actions on our end, and send swings where needed. + session.sendDownstreamGamePacket(new ServerboundSwingPacket(Hand.MAIN_HAND)); + session.activateArmAnimationTicking(); + } + }, + 25, + TimeUnit.MILLISECONDS + ); } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockEntityPickRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockEntityPickRequestTranslator.java index e85456c33..acb8573fb 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockEntityPickRequestTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockEntityPickRequestTranslator.java @@ -51,29 +51,14 @@ public class BedrockEntityPickRequestTranslator extends PacketTranslator { - // Include type of boat in the name - int variant = ((BoatEntity) entity).getVariant(); - String typeOfBoat = switch (variant) { - case 1 -> "spruce"; - case 2 -> "birch"; - case 3 -> "jungle"; - case 4 -> "acacia"; - case 5 -> "cherry"; - case 6 -> "dark_oak"; - case 7 -> "mangrove"; - case 8 -> "bamboo"; - default -> "oak"; - }; - itemName = typeOfBoat + "_" + entity.getDefinition().entityType().name().toLowerCase(Locale.ROOT); - // Bamboo boat is a raft - if (variant == 8) { - itemName = itemName.replace("boat", "raft"); - } - } case LEASH_KNOT -> itemName = "lead"; case CHEST_MINECART, COMMAND_BLOCK_MINECART, FURNACE_MINECART, HOPPER_MINECART, TNT_MINECART -> // The Bedrock identifier matches the item name which moves MINECART to the end of the name diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java index 6ae21067f..422c45b9b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java @@ -30,7 +30,6 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; import org.cloudburstmc.math.vector.Vector3d; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; -import org.cloudburstmc.protocol.bedrock.data.LevelEvent; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; @@ -42,8 +41,8 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.transaction.InventoryTra import org.cloudburstmc.protocol.bedrock.data.inventory.transaction.LegacySetItemSlotData; import org.cloudburstmc.protocol.bedrock.packet.ContainerOpenPacket; import org.cloudburstmc.protocol.bedrock.packet.InventoryTransactionPacket; -import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket; +import org.cloudburstmc.protocol.bedrock.packet.PlaySoundPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.Entity; @@ -53,6 +52,7 @@ import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.PlayerInventory; import org.geysermc.geyser.inventory.click.Click; +import org.geysermc.geyser.inventory.item.GeyserInstrument; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.BlockItem; import org.geysermc.geyser.item.type.BoatItem; @@ -77,6 +77,7 @@ import org.geysermc.geyser.util.CooldownUtils; import org.geysermc.geyser.util.EntityUtils; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InventoryUtils; +import org.geysermc.geyser.util.SoundUtils; import org.geysermc.mcprotocollib.protocol.data.game.Holder; import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; @@ -187,7 +188,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator false; }; if (isGodBridging) { - restoreCorrectBlock(session, blockPos, packet); + restoreCorrectBlock(session, blockPos); return; } } @@ -207,7 +208,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator instrument = session.getPlayerInventory() + if (!session.getWorldCache().hasCooldown(session.getPlayerInventory().getItemInHand())) { + Holder holder = session.getPlayerInventory() .getItemInHand() .getComponent(DataComponentType.INSTRUMENT); - if (instrument != null && instrument.isId()) { - // BDS uses a LevelSoundEvent2Packet, but that doesn't work here... (as of 1.21.20) - LevelSoundEventPacket soundPacket = new LevelSoundEventPacket(); - soundPacket.setSound(SoundEvent.valueOf("GOAT_CALL_" + instrument.id())); - soundPacket.setPosition(session.getPlayerEntity().getPosition()); - soundPacket.setIdentifier("minecraft:player"); - soundPacket.setExtraData(-1); - session.sendUpstreamPacket(soundPacket); + if (holder != null) { + GeyserInstrument instrument = GeyserInstrument.fromHolder(session, holder); + if (instrument.bedrockInstrument() != null) { + // BDS uses a LevelSoundEvent2Packet, but that doesn't work here... (as of 1.21.20) + LevelSoundEventPacket soundPacket = new LevelSoundEventPacket(); + soundPacket.setSound(SoundEvent.valueOf("GOAT_CALL_" + instrument.bedrockInstrument().ordinal())); + soundPacket.setPosition(session.getPlayerEntity().getPosition()); + soundPacket.setIdentifier("minecraft:player"); + soundPacket.setExtraData(-1); + session.sendUpstreamPacket(soundPacket); + } else { + PlaySoundPacket playSoundPacket = new PlaySoundPacket(); + playSoundPacket.setPosition(session.getPlayerEntity().position()); + playSoundPacket.setSound(SoundUtils.translatePlaySound(instrument.soundEvent())); + playSoundPacket.setPitch(1.0F); + playSoundPacket.setVolume(instrument.range() / 16.0F); + session.sendUpstreamPacket(playSoundPacket); + } } } } @@ -423,53 +435,6 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator { - int blockState = session.getGameMode() == GameMode.CREATIVE ? - session.getGeyser().getWorldManager().getBlockAt(session, packet.getBlockPosition()) : session.getBreakingBlock(); - - session.setLastBlockPlaced(null); - session.setLastBlockPlacePosition(null); - - // Same deal with vanilla block placing as above. - if (!session.getWorldBorder().isInsideBorderBoundaries()) { - restoreCorrectBlock(session, packet.getBlockPosition(), packet); - return; - } - - Vector3f playerPosition = session.getPlayerEntity().getPosition(); - playerPosition = playerPosition.down(EntityDefinitions.PLAYER.offset() - session.getEyeHeight()); - - if (!canInteractWithBlock(session, playerPosition, packet.getBlockPosition())) { - restoreCorrectBlock(session, packet.getBlockPosition(), packet); - return; - } - - int sequence = session.getWorldCache().nextPredictionSequence(); - session.getWorldCache().markPositionInSequence(packet.getBlockPosition()); - // -1 means we don't know what block they're breaking - if (blockState == -1) { - blockState = Block.JAVA_AIR_ID; - } - - LevelEventPacket blockBreakPacket = new LevelEventPacket(); - blockBreakPacket.setType(LevelEvent.PARTICLE_DESTROY_BLOCK); - blockBreakPacket.setPosition(packet.getBlockPosition().toFloat()); - blockBreakPacket.setData(session.getBlockMappings().getBedrockBlockId(blockState)); - session.sendUpstreamPacket(blockBreakPacket); - session.setBreakingBlock(-1); - - Entity itemFrameEntity = ItemFrameEntity.getItemFrameEntity(session, packet.getBlockPosition()); - if (itemFrameEntity != null) { - ServerboundInteractPacket attackPacket = new ServerboundInteractPacket(itemFrameEntity.getEntityId(), - InteractAction.ATTACK, session.isSneaking()); - session.sendDownstreamGamePacket(attackPacket); - break; - } - - PlayerAction action = session.getGameMode() == GameMode.CREATIVE ? PlayerAction.START_DIGGING : PlayerAction.FINISH_DIGGING; - ServerboundPlayerActionPacket breakPacket = new ServerboundPlayerActionPacket(action, packet.getBlockPosition(), Direction.VALUES[packet.getBlockFace()], sequence); - session.sendDownstreamGamePacket(breakPacket); - } } break; case ITEM_RELEASE: @@ -549,7 +514,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator { - - @Override - public void translate(GeyserSession session, MoveEntityAbsolutePacket packet) { - session.setLastVehicleMoveTimestamp(System.currentTimeMillis()); - - Entity ridingEntity = session.getPlayerEntity().getVehicle(); - if (ridingEntity != null && session.getWorldBorder().isPassingIntoBorderBoundaries(packet.getPosition(), false)) { - Vector3f position = Vector3f.from(ridingEntity.getPosition().getX(), packet.getPosition().getY(), - ridingEntity.getPosition().getZ()); - if (ridingEntity instanceof BoatEntity) { - // Undo the changes usually applied to the boat - ridingEntity.as(BoatEntity.class) - .moveAbsoluteWithoutAdjustments(position, ridingEntity.getYaw(), - ridingEntity.isOnGround(), true); - } else { - // This doesn't work if teleported is false - ridingEntity.moveAbsolute(position, - ridingEntity.getYaw(), ridingEntity.getPitch(), ridingEntity.getHeadYaw(), - ridingEntity.isOnGround(), true); - } - return; - } - - float y = packet.getPosition().getY(); - if (ridingEntity instanceof BoatEntity && !ridingEntity.isOnGround()) { - // Remove the offset to prevents boats from looking like they're floating in water - y -= EntityDefinitions.BOAT.offset(); - } - ServerboundMoveVehiclePacket ServerboundMoveVehiclePacket = new ServerboundMoveVehiclePacket( - packet.getPosition().getX(), y, packet.getPosition().getZ(), - packet.getRotation().getY() - 90, packet.getRotation().getX() - ); - session.sendDownstreamGamePacket(ServerboundMoveVehiclePacket); - } -} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockPlayerInputTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockPlayerInputTranslator.java deleted file mode 100644 index 1498c2184..000000000 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockPlayerInputTranslator.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser - */ - -package org.geysermc.geyser.translator.protocol.bedrock; - -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundMoveVehiclePacket; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundPlayerInputPacket; -import org.cloudburstmc.math.vector.Vector3f; -import org.cloudburstmc.protocol.bedrock.packet.PlayerInputPacket; -import org.geysermc.geyser.entity.EntityDefinitions; -import org.geysermc.geyser.entity.type.BoatEntity; -import org.geysermc.geyser.entity.type.Entity; -import org.geysermc.geyser.entity.type.living.animal.horse.AbstractHorseEntity; -import org.geysermc.geyser.entity.type.living.animal.horse.LlamaEntity; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.protocol.PacketTranslator; -import org.geysermc.geyser.translator.protocol.Translator; - -/** - * Sent by the client for minecarts and boats. - */ -@Translator(packet = PlayerInputPacket.class) -public class BedrockPlayerInputTranslator extends PacketTranslator { - - @Override - public void translate(GeyserSession session, PlayerInputPacket packet) { - ServerboundPlayerInputPacket playerInputPacket = new ServerboundPlayerInputPacket( - packet.getInputMotion().getX(), packet.getInputMotion().getY(), packet.isJumping(), packet.isSneaking() - ); - - session.sendDownstreamGamePacket(playerInputPacket); - - session.getPlayerEntity().setVehicleInput(packet.getInputMotion()); - - // Bedrock only sends movement vehicle packets while moving - // This allows horses to take damage while standing on magma - Entity vehicle = session.getPlayerEntity().getVehicle(); - boolean sendMovement = false; - if (vehicle instanceof AbstractHorseEntity && !(vehicle instanceof LlamaEntity)) { - sendMovement = vehicle.isOnGround(); - } else if (vehicle instanceof BoatEntity) { - if (vehicle.getPassengers().size() == 1) { - // The player is the only rider - sendMovement = true; - } else { - // Check if the player is the front rider - if (session.getPlayerEntity().isRidingInFront()) { - sendMovement = true; - } - } - } - if (sendMovement) { - long timeSinceVehicleMove = System.currentTimeMillis() - session.getLastVehicleMoveTimestamp(); - if (timeSinceVehicleMove >= 100) { - Vector3f vehiclePosition = vehicle.getPosition(); - - if (vehicle instanceof BoatEntity && !vehicle.isOnGround()) { - // Remove some Y position to prevents boats flying up - vehiclePosition = vehiclePosition.down(EntityDefinitions.BOAT.offset()); - } - - ServerboundMoveVehiclePacket moveVehiclePacket = new ServerboundMoveVehiclePacket( - vehiclePosition.getX(), vehiclePosition.getY(), vehiclePosition.getZ(), - vehicle.getYaw() - 90, vehicle.getPitch() - ); - session.sendDownstreamGamePacket(moveVehiclePacket); - } - } - } -} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockActionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockActionTranslator.java deleted file mode 100644 index cd1300a13..000000000 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockActionTranslator.java +++ /dev/null @@ -1,387 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser - */ - -package org.geysermc.geyser.translator.protocol.bedrock.entity.player; - -import org.cloudburstmc.math.vector.Vector3f; -import org.cloudburstmc.math.vector.Vector3i; -import org.cloudburstmc.protocol.bedrock.data.LevelEvent; -import org.cloudburstmc.protocol.bedrock.data.PlayerActionType; -import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; -import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType; -import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; -import org.cloudburstmc.protocol.bedrock.packet.AnimatePacket; -import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket; -import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; -import org.cloudburstmc.protocol.bedrock.packet.PlayStatusPacket; -import org.cloudburstmc.protocol.bedrock.packet.PlayerActionPacket; -import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket; -import org.geysermc.geyser.api.block.custom.CustomBlockState; -import org.geysermc.geyser.entity.type.Entity; -import org.geysermc.geyser.entity.type.ItemFrameEntity; -import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; -import org.geysermc.geyser.inventory.GeyserItemStack; -import org.geysermc.geyser.level.block.Blocks; -import org.geysermc.geyser.level.block.property.Properties; -import org.geysermc.geyser.level.block.type.Block; -import org.geysermc.geyser.level.block.type.BlockState; -import org.geysermc.geyser.registry.BlockRegistries; -import org.geysermc.geyser.registry.type.ItemMapping; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.session.cache.SkullCache; -import org.geysermc.geyser.translator.item.CustomItemTranslator; -import org.geysermc.geyser.translator.protocol.PacketTranslator; -import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.geyser.util.BlockUtils; -import org.geysermc.geyser.util.CooldownUtils; -import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction; -import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; -import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; -import org.geysermc.mcprotocollib.protocol.data.game.entity.player.InteractAction; -import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerAction; -import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerState; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerCommandPacket; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundSwingPacket; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundUseItemOnPacket; - -@Translator(packet = PlayerActionPacket.class) -public class BedrockActionTranslator extends PacketTranslator { - - @Override - public void translate(GeyserSession session, PlayerActionPacket packet) { - SessionPlayerEntity entity = session.getPlayerEntity(); - - // Send book update before any player action - if (packet.getAction() != PlayerActionType.RESPAWN) { - session.getBookEditCache().checkForSend(); - } - - Vector3i vector = packet.getBlockPosition(); - - switch (packet.getAction()) { - case RESPAWN -> { - // Respawn process is finished and the server and client are both OK with respawning. - EntityEventPacket eventPacket = new EntityEventPacket(); - eventPacket.setRuntimeEntityId(entity.getGeyserId()); - eventPacket.setType(EntityEventType.RESPAWN); - eventPacket.setData(0); - session.sendUpstreamPacket(eventPacket); - // Resend attributes or else in rare cases the user can think they're not dead when they are, upon joining the server - UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket(); - attributesPacket.setRuntimeEntityId(entity.getGeyserId()); - attributesPacket.getAttributes().addAll(entity.getAttributes().values()); - session.sendUpstreamPacket(attributesPacket); - - // Bounding box must be sent after a player dies and respawns since 1.19.40 - entity.updateBoundingBox(); - - // Needed here since 1.19.81 for dimension switching - session.getEntityCache().updateBossBars(); - } - case START_SWIMMING -> { - if (!entity.getFlag(EntityFlag.SWIMMING)) { - ServerboundPlayerCommandPacket startSwimPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SPRINTING); - session.sendDownstreamGamePacket(startSwimPacket); - - session.setSwimming(true); - } - } - case STOP_SWIMMING -> { - // Prevent packet spam when Bedrock players are crawling near the edge of a block - if (!session.getCollisionManager().mustPlayerCrawlHere()) { - ServerboundPlayerCommandPacket stopSwimPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.STOP_SPRINTING); - session.sendDownstreamGamePacket(stopSwimPacket); - - session.setSwimming(false); - } - } - case START_GLIDE -> { - // Otherwise gliding will not work in creative - ServerboundPlayerAbilitiesPacket playerAbilitiesPacket = new ServerboundPlayerAbilitiesPacket(false); - session.sendDownstreamGamePacket(playerAbilitiesPacket); - sendPlayerGlideToggle(session, entity); - } - case STOP_GLIDE -> sendPlayerGlideToggle(session, entity); - case START_SNEAK -> { - ServerboundPlayerCommandPacket startSneakPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SNEAKING); - session.sendDownstreamGamePacket(startSneakPacket); - - session.startSneaking(); - } - case STOP_SNEAK -> { - ServerboundPlayerCommandPacket stopSneakPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.STOP_SNEAKING); - session.sendDownstreamGamePacket(stopSneakPacket); - - session.stopSneaking(); - } - case START_SPRINT -> { - if (!entity.getFlag(EntityFlag.SWIMMING)) { - ServerboundPlayerCommandPacket startSprintPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SPRINTING); - session.sendDownstreamGamePacket(startSprintPacket); - session.setSprinting(true); - } - } - case STOP_SPRINT -> { - if (!entity.getFlag(EntityFlag.SWIMMING)) { - ServerboundPlayerCommandPacket stopSprintPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.STOP_SPRINTING); - session.sendDownstreamGamePacket(stopSprintPacket); - } - session.setSprinting(false); - } - case DROP_ITEM -> { - ServerboundPlayerActionPacket dropItemPacket = new ServerboundPlayerActionPacket(PlayerAction.DROP_ITEM, - vector, Direction.VALUES[packet.getFace()], 0); - session.sendDownstreamGamePacket(dropItemPacket); - } - case STOP_SLEEP -> { - ServerboundPlayerCommandPacket stopSleepingPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.LEAVE_BED); - session.sendDownstreamGamePacket(stopSleepingPacket); - } - case START_BREAK -> { - // Ignore START_BREAK when the player is CREATIVE to avoid Spigot receiving 2 packets it interpets as block breaking. https://github.com/GeyserMC/Geyser/issues/4021 - if (session.getGameMode() == GameMode.CREATIVE) { - break; - } - - // Start the block breaking animation - int blockState = session.getGeyser().getWorldManager().getBlockAt(session, vector); - LevelEventPacket startBreak = new LevelEventPacket(); - startBreak.setType(LevelEvent.BLOCK_START_BREAK); - startBreak.setPosition(vector.toFloat()); - double breakTime = BlockUtils.getSessionBreakTime(session, BlockState.of(blockState).block()) * 20; - - // If the block is custom or the breaking item is custom, we must keep track of break time ourselves - GeyserItemStack item = session.getPlayerInventory().getItemInHand(); - ItemMapping mapping = item.getMapping(session); - ItemDefinition customItem = mapping.isTool() ? CustomItemTranslator.getCustomItem(item.getComponents(), mapping) : null; - CustomBlockState blockStateOverride = BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.get(blockState); - SkullCache.Skull skull = session.getSkullCache().getSkulls().get(vector); - - session.setBlockBreakStartTime(0); - if (blockStateOverride != null || customItem != null || (skull != null && skull.getBlockDefinition() != null)) { - session.setBlockBreakStartTime(System.currentTimeMillis()); - } - startBreak.setData((int) (65535 / breakTime)); - session.setBreakingBlock(blockState); - session.sendUpstreamPacket(startBreak); - - // Account for fire - the client likes to hit the block behind. - Vector3i fireBlockPos = BlockUtils.getBlockPosition(vector, packet.getFace()); - Block block = session.getGeyser().getWorldManager().blockAt(session, fireBlockPos).block(); - Direction direction = Direction.VALUES[packet.getFace()]; - if (block == Blocks.FIRE || block == Blocks.SOUL_FIRE) { - ServerboundPlayerActionPacket startBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.START_DIGGING, fireBlockPos, - direction, session.getWorldCache().nextPredictionSequence()); - session.sendDownstreamGamePacket(startBreakingPacket); - } - - ServerboundPlayerActionPacket startBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.START_DIGGING, - vector, direction, session.getWorldCache().nextPredictionSequence()); - session.sendDownstreamGamePacket(startBreakingPacket); - - spawnBlockBreakParticles(session, direction, vector, BlockState.of(blockState)); - } - case CONTINUE_BREAK -> { - if (session.getGameMode() == GameMode.CREATIVE) { - break; - } - int breakingBlock = session.getBreakingBlock(); - if (breakingBlock == -1) { - breakingBlock = Block.JAVA_AIR_ID; - } - - Vector3f vectorFloat = vector.toFloat(); - - BlockState breakingBlockState = BlockState.of(breakingBlock); - Direction direction = Direction.VALUES[packet.getFace()]; - spawnBlockBreakParticles(session, direction, vector, breakingBlockState); - - double breakTime = BlockUtils.getSessionBreakTime(session, breakingBlockState.block()) * 20; - // If the block is custom, we must keep track of when it should break ourselves - long blockBreakStartTime = session.getBlockBreakStartTime(); - if (blockBreakStartTime != 0) { - long timeSinceStart = System.currentTimeMillis() - blockBreakStartTime; - // We need to add a slight delay to the break time, otherwise the client breaks blocks too fast - if (timeSinceStart >= (breakTime += 2) * 50) { - // Play break sound and particle - LevelEventPacket effectPacket = new LevelEventPacket(); - effectPacket.setPosition(vectorFloat); - effectPacket.setType(LevelEvent.PARTICLE_DESTROY_BLOCK); - effectPacket.setData(session.getBlockMappings().getBedrockBlockId(breakingBlock)); - session.sendUpstreamPacket(effectPacket); - - // Break the block - ServerboundPlayerActionPacket finishBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.FINISH_DIGGING, - vector, direction, session.getWorldCache().nextPredictionSequence()); - session.sendDownstreamGamePacket(finishBreakingPacket); - session.setBlockBreakStartTime(0); - break; - } - } - // Update the break time in the event that player conditions changed (jumping, effects applied) - LevelEventPacket updateBreak = new LevelEventPacket(); - updateBreak.setType(LevelEvent.BLOCK_UPDATE_BREAK); - updateBreak.setPosition(vectorFloat); - updateBreak.setData((int) (65535 / breakTime)); - session.sendUpstreamPacket(updateBreak); - } - case ABORT_BREAK -> { - if (session.getGameMode() != GameMode.CREATIVE) { - // As of 1.16.210: item frame items are taken out here. - // Survival also sends START_BREAK, but by attaching our process here adventure mode also works - Entity itemFrameEntity = ItemFrameEntity.getItemFrameEntity(session, vector); - if (itemFrameEntity != null) { - ServerboundInteractPacket interactPacket = new ServerboundInteractPacket(itemFrameEntity.getEntityId(), - InteractAction.ATTACK, Hand.MAIN_HAND, session.isSneaking()); - session.sendDownstreamGamePacket(interactPacket); - break; - } - } - - ServerboundPlayerActionPacket abortBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.CANCEL_DIGGING, vector, Direction.DOWN, 0); - session.sendDownstreamGamePacket(abortBreakingPacket); - LevelEventPacket stopBreak = new LevelEventPacket(); - stopBreak.setType(LevelEvent.BLOCK_STOP_BREAK); - stopBreak.setPosition(vector.toFloat()); - stopBreak.setData(0); - session.setBreakingBlock(-1); - session.sendUpstreamPacket(stopBreak); - } - // Handled in BedrockInventoryTransactionTranslator - case STOP_BREAK -> { - } - case DIMENSION_CHANGE_SUCCESS -> { - //sometimes the client doesn't feel like loading - PlayStatusPacket spawnPacket = new PlayStatusPacket(); - spawnPacket.setStatus(PlayStatusPacket.Status.PLAYER_SPAWN); - session.sendUpstreamPacket(spawnPacket); - - UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket(); - attributesPacket.setRuntimeEntityId(entity.getGeyserId()); - attributesPacket.getAttributes().addAll(entity.getAttributes().values()); - session.sendUpstreamPacket(attributesPacket); - } - case JUMP -> entity.setOnGround(false); // Increase block break time while jumping - case MISSED_SWING -> { - // Java edition sends a cooldown when hitting air. - // Normally handled by BedrockLevelSoundEventTranslator, but there is no sound on Java for this. - CooldownUtils.sendCooldown(session); - - // TODO Re-evaluate after pre-1.20.10 is no longer supported? - if (session.getArmAnimationTicks() == -1) { - session.sendDownstreamGamePacket(new ServerboundSwingPacket(Hand.MAIN_HAND)); - session.activateArmAnimationTicking(); - - // Send packet to Bedrock so it knows - AnimatePacket animatePacket = new AnimatePacket(); - animatePacket.setRuntimeEntityId(session.getPlayerEntity().getGeyserId()); - animatePacket.setAction(AnimatePacket.Action.SWING_ARM); - session.sendUpstreamPacket(animatePacket); - } - } - case START_FLYING -> { // Since 1.20.30 - if (session.isCanFly()) { - if (session.getGameMode() == GameMode.SPECTATOR) { - // should already be flying - session.sendAdventureSettings(); - break; - } - - if (session.getPlayerEntity().getFlag(EntityFlag.SWIMMING) && session.getCollisionManager().isPlayerInWater()) { - // As of 1.18.1, Java Edition cannot fly while in water, but it can fly while crawling - // If this isn't present, swimming on a 1.13.2 server and then attempting to fly will put you into a flying/swimming state that is invalid on JE - session.sendAdventureSettings(); - break; - } - - session.setFlying(true); - session.sendDownstreamGamePacket(new ServerboundPlayerAbilitiesPacket(true)); - } else { - // update whether we can fly - session.sendAdventureSettings(); - // stop flying - PlayerActionPacket stopFlyingPacket = new PlayerActionPacket(); - stopFlyingPacket.setRuntimeEntityId(session.getPlayerEntity().getGeyserId()); - stopFlyingPacket.setAction(PlayerActionType.STOP_FLYING); - stopFlyingPacket.setBlockPosition(Vector3i.ZERO); - stopFlyingPacket.setResultPosition(Vector3i.ZERO); - stopFlyingPacket.setFace(0); - session.sendUpstreamPacket(stopFlyingPacket); - } - } - case STOP_FLYING -> { - session.setFlying(false); - session.sendDownstreamGamePacket(new ServerboundPlayerAbilitiesPacket(false)); - } - case DIMENSION_CHANGE_REQUEST_OR_CREATIVE_DESTROY_BLOCK -> { // Used by client to get book from lecterns and items from item frame in creative mode since 1.20.70 - BlockState state = session.getGeyser().getWorldManager().blockAt(session, vector); - - if (state.getValue(Properties.HAS_BOOK, false)) { - session.setDroppingLecternBook(true); - - ServerboundUseItemOnPacket blockPacket = new ServerboundUseItemOnPacket( - vector, - Direction.DOWN, - Hand.MAIN_HAND, - 0, 0, 0, - false, - session.getWorldCache().nextPredictionSequence()); - session.sendDownstreamGamePacket(blockPacket); - break; - } - - Entity itemFrame = ItemFrameEntity.getItemFrameEntity(session, packet.getBlockPosition()); - if (itemFrame != null) { - ServerboundInteractPacket interactPacket = new ServerboundInteractPacket(itemFrame.getEntityId(), - InteractAction.ATTACK, Hand.MAIN_HAND, session.isSneaking()); - session.sendDownstreamGamePacket(interactPacket); - } - } - } - } - - private void spawnBlockBreakParticles(GeyserSession session, Direction direction, Vector3i position, BlockState blockState) { - LevelEventPacket levelEventPacket = new LevelEventPacket(); - switch (direction) { - case UP -> levelEventPacket.setType(LevelEvent.PARTICLE_BREAK_BLOCK_UP); - case DOWN -> levelEventPacket.setType(LevelEvent.PARTICLE_BREAK_BLOCK_DOWN); - case NORTH -> levelEventPacket.setType(LevelEvent.PARTICLE_BREAK_BLOCK_NORTH); - case EAST -> levelEventPacket.setType(LevelEvent.PARTICLE_BREAK_BLOCK_EAST); - case SOUTH -> levelEventPacket.setType(LevelEvent.PARTICLE_BREAK_BLOCK_SOUTH); - case WEST -> levelEventPacket.setType(LevelEvent.PARTICLE_BREAK_BLOCK_WEST); - } - levelEventPacket.setPosition(position.toFloat()); - levelEventPacket.setData(session.getBlockMappings().getBedrockBlock(blockState).getRuntimeId()); - session.sendUpstreamPacket(levelEventPacket); - } - - private void sendPlayerGlideToggle(GeyserSession session, Entity entity) { - ServerboundPlayerCommandPacket glidePacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_ELYTRA_FLYING); - session.sendDownstreamGamePacket(glidePacket); - } -} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockInteractTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockInteractTranslator.java index 20c1b055d..2df77ad16 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockInteractTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockInteractTranslator.java @@ -25,16 +25,11 @@ package org.geysermc.geyser.translator.protocol.bedrock.entity.player; -import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; -import org.geysermc.mcprotocollib.protocol.data.game.entity.player.InteractAction; -import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerState; -import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerCommandPacket; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityLinkData; import org.cloudburstmc.protocol.bedrock.packet.InteractPacket; import org.cloudburstmc.protocol.bedrock.packet.SetEntityLinkPacket; +import org.geysermc.geyser.entity.type.ChestBoatEntity; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.living.animal.horse.AbstractHorseEntity; import org.geysermc.geyser.item.Items; @@ -42,6 +37,11 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.util.InventoryUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.InteractAction; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerState; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerCommandPacket; import java.util.concurrent.TimeUnit; @@ -119,7 +119,7 @@ public class BedrockInteractTranslator extends PacketTranslator case OPEN_INVENTORY: if (session.getOpenInventory() == null) { Entity ridingEntity = session.getPlayerEntity().getVehicle(); - if (ridingEntity instanceof AbstractHorseEntity || (ridingEntity != null && ridingEntity.getDefinition().entityType() == EntityType.CHEST_BOAT)) { + if (ridingEntity instanceof AbstractHorseEntity || ridingEntity instanceof ChestBoatEntity) { // This mob has an inventory of its own that we should open instead. ServerboundPlayerCommandPacket openVehicleWindowPacket = new ServerboundPlayerCommandPacket(session.getPlayerEntity().getEntityId(), PlayerState.OPEN_VEHICLE_INVENTORY); session.sendDownstreamGamePacket(openVehicleWindowPacket); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerActionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerActionTranslator.java new file mode 100644 index 000000000..797505e99 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockPlayerActionTranslator.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2024 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.translator.protocol.bedrock.entity.player; + +import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType; +import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket; +import org.cloudburstmc.protocol.bedrock.packet.PlayStatusPacket; +import org.cloudburstmc.protocol.bedrock.packet.PlayerActionPacket; +import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket; +import org.geysermc.geyser.entity.type.Entity; +import org.geysermc.geyser.entity.type.ItemFrameEntity; +import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; +import org.geysermc.geyser.level.block.property.Properties; +import org.geysermc.geyser.level.block.type.BlockState; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.protocol.PacketTranslator; +import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.InteractAction; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerState; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerCommandPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundUseItemOnPacket; + +@Translator(packet = PlayerActionPacket.class) +public class BedrockPlayerActionTranslator extends PacketTranslator { + + @Override + public void translate(GeyserSession session, PlayerActionPacket packet) { + // This packet was used more before server auth movement was needed, but it's still used for a couple things... + switch (packet.getAction()) { + case RESPAWN -> { + SessionPlayerEntity entity = session.getPlayerEntity(); + // Respawn process is finished and the server and client are both OK with respawning. + EntityEventPacket eventPacket = new EntityEventPacket(); + eventPacket.setRuntimeEntityId(entity.getGeyserId()); + eventPacket.setType(EntityEventType.RESPAWN); + eventPacket.setData(0); + session.sendUpstreamPacket(eventPacket); + // Resend attributes or else in rare cases the user can think they're not dead when they are, upon joining the server + UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket(); + attributesPacket.setRuntimeEntityId(entity.getGeyserId()); + attributesPacket.getAttributes().addAll(entity.getAttributes().values()); + session.sendUpstreamPacket(attributesPacket); + + // Bounding box must be sent after a player dies and respawns since 1.19.40 + entity.updateBoundingBox(); + + // Needed here since 1.19.81 for dimension switching + session.getEntityCache().updateBossBars(); + } + case STOP_SLEEP -> { + ServerboundPlayerCommandPacket stopSleepingPacket = new ServerboundPlayerCommandPacket(session.getPlayerEntity().getEntityId(), PlayerState.LEAVE_BED); + session.sendDownstreamGamePacket(stopSleepingPacket); + } + case DIMENSION_CHANGE_REQUEST_OR_CREATIVE_DESTROY_BLOCK -> { // Used by client to get book from lecterns and items from item frame in creative mode since 1.20.70 + Vector3i vector = packet.getBlockPosition(); + BlockState state = session.getGeyser().getWorldManager().blockAt(session, vector); + + if (state.getValue(Properties.HAS_BOOK, false)) { + session.setDroppingLecternBook(true); + + ServerboundUseItemOnPacket blockPacket = new ServerboundUseItemOnPacket( + vector, + Direction.DOWN, + Hand.MAIN_HAND, + 0, 0, 0, + false, + false, + session.getWorldCache().nextPredictionSequence()); + session.sendDownstreamGamePacket(blockPacket); + break; + } + + Entity itemFrame = ItemFrameEntity.getItemFrameEntity(session, vector); + if (itemFrame != null) { + ServerboundInteractPacket interactPacket = new ServerboundInteractPacket(itemFrame.getEntityId(), + InteractAction.ATTACK, Hand.MAIN_HAND, session.isSneaking()); + session.sendDownstreamGamePacket(interactPacket); + } + } + case DIMENSION_CHANGE_SUCCESS -> { + SessionPlayerEntity entity = session.getPlayerEntity(); + // Sometimes the client doesn't feel like loading + PlayStatusPacket spawnPacket = new PlayStatusPacket(); + spawnPacket.setStatus(PlayStatusPacket.Status.PLAYER_SPAWN); + session.sendUpstreamPacket(spawnPacket); + + UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket(); + attributesPacket.setRuntimeEntityId(entity.getGeyserId()); + attributesPacket.getAttributes().addAll(entity.getAttributes().values()); + session.sendUpstreamPacket(attributesPacket); + } + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockBlockActions.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockBlockActions.java new file mode 100644 index 000000000..061a04b77 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockBlockActions.java @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2019-2024 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.translator.protocol.bedrock.entity.player.input; + +import org.cloudburstmc.math.vector.Vector3f; +import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.protocol.bedrock.data.LevelEvent; +import org.cloudburstmc.protocol.bedrock.data.PlayerActionType; +import org.cloudburstmc.protocol.bedrock.data.PlayerBlockActionData; +import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; +import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; +import org.geysermc.geyser.api.block.custom.CustomBlockState; +import org.geysermc.geyser.entity.type.Entity; +import org.geysermc.geyser.entity.type.ItemFrameEntity; +import org.geysermc.geyser.inventory.GeyserItemStack; +import org.geysermc.geyser.level.block.Blocks; +import org.geysermc.geyser.level.block.type.Block; +import org.geysermc.geyser.level.block.type.BlockState; +import org.geysermc.geyser.registry.BlockRegistries; +import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.SkullCache; +import org.geysermc.geyser.translator.item.CustomItemTranslator; +import org.geysermc.geyser.util.BlockUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.InteractAction; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerAction; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket; + +import java.util.List; + +final class BedrockBlockActions { + + static void translate(GeyserSession session, List playerActions) { + // Send book update before any player action + session.getBookEditCache().checkForSend(); + + for (PlayerBlockActionData blockActionData : playerActions) { + handle(session, blockActionData); + } + } + + private static void handle(GeyserSession session, PlayerBlockActionData blockActionData) { + PlayerActionType action = blockActionData.getAction(); + Vector3i vector = blockActionData.getBlockPosition(); + int blockFace = blockActionData.getFace(); + + switch (action) { + case DROP_ITEM -> { + ServerboundPlayerActionPacket dropItemPacket = new ServerboundPlayerActionPacket(PlayerAction.DROP_ITEM, + vector, Direction.VALUES[blockFace], 0); + session.sendDownstreamGamePacket(dropItemPacket); + } + case START_BREAK -> { + // Ignore START_BREAK when the player is CREATIVE to avoid Spigot receiving 2 packets it interpets as block breaking. https://github.com/GeyserMC/Geyser/issues/4021 + if (session.getGameMode() == GameMode.CREATIVE) { + break; + } + + // Start the block breaking animation + int blockState = session.getGeyser().getWorldManager().getBlockAt(session, vector); + LevelEventPacket startBreak = new LevelEventPacket(); + startBreak.setType(LevelEvent.BLOCK_START_BREAK); + startBreak.setPosition(vector.toFloat()); + double breakTime = BlockUtils.getSessionBreakTime(session, BlockState.of(blockState).block()) * 20; + + // If the block is custom or the breaking item is custom, we must keep track of break time ourselves + GeyserItemStack item = session.getPlayerInventory().getItemInHand(); + ItemMapping mapping = item.getMapping(session); + ItemDefinition customItem = mapping.isTool() ? CustomItemTranslator.getCustomItem(item.getComponents(), mapping) : null; + CustomBlockState blockStateOverride = BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.get(blockState); + SkullCache.Skull skull = session.getSkullCache().getSkulls().get(vector); + + session.setBlockBreakStartTime(0); + if (blockStateOverride != null || customItem != null || (skull != null && skull.getBlockDefinition() != null)) { + session.setBlockBreakStartTime(System.currentTimeMillis()); + } + startBreak.setData((int) (65535 / breakTime)); + session.setBreakingBlock(blockState); + session.sendUpstreamPacket(startBreak); + + // Account for fire - the client likes to hit the block behind. + Vector3i fireBlockPos = BlockUtils.getBlockPosition(vector, blockFace); + Block block = session.getGeyser().getWorldManager().blockAt(session, fireBlockPos).block(); + Direction direction = Direction.VALUES[blockFace]; + if (block == Blocks.FIRE || block == Blocks.SOUL_FIRE) { + ServerboundPlayerActionPacket startBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.START_DIGGING, fireBlockPos, + direction, session.getWorldCache().nextPredictionSequence()); + session.sendDownstreamGamePacket(startBreakingPacket); + } + + ServerboundPlayerActionPacket startBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.START_DIGGING, + vector, direction, session.getWorldCache().nextPredictionSequence()); + session.sendDownstreamGamePacket(startBreakingPacket); + + spawnBlockBreakParticles(session, direction, vector, BlockState.of(blockState)); + } + case CONTINUE_BREAK -> { + if (session.getGameMode() == GameMode.CREATIVE) { + break; + } + int breakingBlock = session.getBreakingBlock(); + if (breakingBlock == -1) { + breakingBlock = Block.JAVA_AIR_ID; + } + + Vector3f vectorFloat = vector.toFloat(); + + BlockState breakingBlockState = BlockState.of(breakingBlock); + Direction direction = Direction.VALUES[blockFace]; + spawnBlockBreakParticles(session, direction, vector, breakingBlockState); + + double breakTime = BlockUtils.getSessionBreakTime(session, breakingBlockState.block()) * 20; + // If the block is custom, we must keep track of when it should break ourselves + long blockBreakStartTime = session.getBlockBreakStartTime(); + if (blockBreakStartTime != 0) { + long timeSinceStart = System.currentTimeMillis() - blockBreakStartTime; + // We need to add a slight delay to the break time, otherwise the client breaks blocks too fast + if (timeSinceStart >= (breakTime += 2) * 50) { + // Play break sound and particle + LevelEventPacket effectPacket = new LevelEventPacket(); + effectPacket.setPosition(vectorFloat); + effectPacket.setType(LevelEvent.PARTICLE_DESTROY_BLOCK); + effectPacket.setData(session.getBlockMappings().getBedrockBlockId(breakingBlock)); + session.sendUpstreamPacket(effectPacket); + + // Break the block + ServerboundPlayerActionPacket finishBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.FINISH_DIGGING, + vector, direction, session.getWorldCache().nextPredictionSequence()); + session.sendDownstreamGamePacket(finishBreakingPacket); + session.setBlockBreakStartTime(0); + break; + } + } + // Update the break time in the event that player conditions changed (jumping, effects applied) + LevelEventPacket updateBreak = new LevelEventPacket(); + updateBreak.setType(LevelEvent.BLOCK_UPDATE_BREAK); + updateBreak.setPosition(vectorFloat); + updateBreak.setData((int) (65535 / breakTime)); + session.sendUpstreamPacket(updateBreak); + } + case ABORT_BREAK -> { + if (session.getGameMode() != GameMode.CREATIVE) { + // As of 1.16.210: item frame items are taken out here. + // Survival also sends START_BREAK, but by attaching our process here adventure mode also works + Entity itemFrameEntity = ItemFrameEntity.getItemFrameEntity(session, vector); + if (itemFrameEntity != null) { + ServerboundInteractPacket interactPacket = new ServerboundInteractPacket(itemFrameEntity.getEntityId(), + InteractAction.ATTACK, Hand.MAIN_HAND, session.isSneaking()); + session.sendDownstreamGamePacket(interactPacket); + break; + } + } + + ServerboundPlayerActionPacket abortBreakingPacket = new ServerboundPlayerActionPacket(PlayerAction.CANCEL_DIGGING, vector, Direction.DOWN, 0); + session.sendDownstreamGamePacket(abortBreakingPacket); + LevelEventPacket stopBreak = new LevelEventPacket(); + stopBreak.setType(LevelEvent.BLOCK_STOP_BREAK); + stopBreak.setPosition(vector.toFloat()); + stopBreak.setData(0); + session.setBreakingBlock(-1); + session.sendUpstreamPacket(stopBreak); + } + // Handled in BedrockInventoryTransactionTranslator + case STOP_BREAK -> { + } + } + } + + private static void spawnBlockBreakParticles(GeyserSession session, Direction direction, Vector3i position, BlockState blockState) { + LevelEventPacket levelEventPacket = new LevelEventPacket(); + switch (direction) { + case UP -> levelEventPacket.setType(LevelEvent.PARTICLE_BREAK_BLOCK_UP); + case DOWN -> levelEventPacket.setType(LevelEvent.PARTICLE_BREAK_BLOCK_DOWN); + case NORTH -> levelEventPacket.setType(LevelEvent.PARTICLE_BREAK_BLOCK_NORTH); + case EAST -> levelEventPacket.setType(LevelEvent.PARTICLE_BREAK_BLOCK_EAST); + case SOUTH -> levelEventPacket.setType(LevelEvent.PARTICLE_BREAK_BLOCK_SOUTH); + case WEST -> levelEventPacket.setType(LevelEvent.PARTICLE_BREAK_BLOCK_WEST); + } + levelEventPacket.setPosition(position.toFloat()); + levelEventPacket.setData(session.getBlockMappings().getBedrockBlock(blockState).getRuntimeId()); + session.sendUpstreamPacket(levelEventPacket); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockMovePlayerTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockMovePlayer.java similarity index 73% rename from core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockMovePlayerTranslator.java rename to core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockMovePlayer.java index ee80cac16..6220b6623 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockMovePlayerTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/input/BedrockMovePlayer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2024 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,42 +23,45 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.translator.protocol.bedrock.entity.player; +package org.geysermc.geyser.translator.protocol.bedrock.entity.player.input; import org.cloudburstmc.math.vector.Vector3d; import org.cloudburstmc.math.vector.Vector3f; -import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket; +import org.cloudburstmc.protocol.bedrock.data.PlayerAuthInputData; +import org.cloudburstmc.protocol.bedrock.packet.PlayerAuthInputPacket; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; -import org.geysermc.geyser.entity.vehicle.ClientVehicle; +import org.geysermc.geyser.level.physics.CollisionResult; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; -import org.geysermc.geyser.translator.protocol.PacketTranslator; -import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.mcprotocollib.network.packet.Packet; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosRotPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerRotPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerStatusOnlyPacket; -@Translator(packet = MovePlayerPacket.class) -public class BedrockMovePlayerTranslator extends PacketTranslator { +/** + * Holds processing input coming in from the {@link PlayerAuthInputPacket} packet. + */ +final class BedrockMovePlayer { - @Override - public void translate(GeyserSession session, MovePlayerPacket packet) { + static void translate(GeyserSession session, PlayerAuthInputPacket packet) { SessionPlayerEntity entity = session.getPlayerEntity(); if (!session.isSpawned()) return; - session.setLastMovementTimestamp(System.currentTimeMillis()); - - // Send book update before the player moves - session.getBookEditCache().checkForSend(); - // Ignore movement packets until Bedrock's position matches the teleported position if (session.getUnconfirmedTeleport() != null) { session.confirmTeleport(packet.getPosition().toDouble().sub(0, EntityDefinitions.PLAYER.offset(), 0)); return; } + boolean actualPositionChanged = !entity.getPosition().equals(packet.getPosition()); + + if (actualPositionChanged) { + // Send book update before the player moves + session.getBookEditCache().checkForSend(); + } + if (entity.getBedPosition() != null) { // https://github.com/GeyserMC/Geyser/issues/5001 // Bedrock 1.21.22 started sending a MovePlayerPacket as soon as it got into a bed. @@ -70,8 +73,11 @@ public class BedrockMovePlayerTranslator extends PacketTranslator { + + @Override + public void translate(GeyserSession session, PlayerAuthInputPacket packet) { + SessionPlayerEntity entity = session.getPlayerEntity(); + + boolean wasJumping = session.getInputCache().wasJumping(); + session.getInputCache().processInputs(packet); + + BedrockMovePlayer.translate(session, packet); + + processVehicleInput(session, packet, wasJumping); + + Set inputData = packet.getInputData(); + for (PlayerAuthInputData input : inputData) { + switch (input) { + case PERFORM_ITEM_INTERACTION -> processItemUseTransaction(session, packet.getItemUseTransaction()); + case PERFORM_BLOCK_ACTIONS -> BedrockBlockActions.translate(session, packet.getPlayerActions()); + case START_SNEAKING -> { + ServerboundPlayerCommandPacket startSneakPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SNEAKING); + session.sendDownstreamGamePacket(startSneakPacket); + + session.startSneaking(); + } + case STOP_SNEAKING -> { + ServerboundPlayerCommandPacket stopSneakPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.STOP_SNEAKING); + session.sendDownstreamGamePacket(stopSneakPacket); + + session.stopSneaking(); + } + case START_SPRINTING -> { + if (!entity.getFlag(EntityFlag.SWIMMING)) { + ServerboundPlayerCommandPacket startSprintPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SPRINTING); + session.sendDownstreamGamePacket(startSprintPacket); + session.setSprinting(true); + } + } + case STOP_SPRINTING -> { + if (!entity.getFlag(EntityFlag.SWIMMING)) { + ServerboundPlayerCommandPacket stopSprintPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.STOP_SPRINTING); + session.sendDownstreamGamePacket(stopSprintPacket); + } + session.setSprinting(false); + } + case START_SWIMMING -> session.setSwimming(true); + case STOP_SWIMMING -> session.setSwimming(false); + case START_CRAWLING -> session.setCrawling(true); + case STOP_CRAWLING -> session.setCrawling(false); + case START_FLYING -> { // Since 1.20.30 + if (session.isCanFly()) { + if (session.getGameMode() == GameMode.SPECTATOR) { + // should already be flying + session.sendAdventureSettings(); + break; + } + + if (session.getPlayerEntity().getFlag(EntityFlag.SWIMMING) && session.getCollisionManager().isPlayerInWater()) { + // As of 1.18.1, Java Edition cannot fly while in water, but it can fly while crawling + // If this isn't present, swimming on a 1.13.2 server and then attempting to fly will put you into a flying/swimming state that is invalid on JE + session.sendAdventureSettings(); + break; + } + + session.setFlying(true); + session.sendDownstreamGamePacket(new ServerboundPlayerAbilitiesPacket(true)); + } else { + // update whether we can fly + session.sendAdventureSettings(); + // stop flying + PlayerActionPacket stopFlyingPacket = new PlayerActionPacket(); + stopFlyingPacket.setRuntimeEntityId(session.getPlayerEntity().getGeyserId()); + stopFlyingPacket.setAction(PlayerActionType.STOP_FLYING); + stopFlyingPacket.setBlockPosition(Vector3i.ZERO); + stopFlyingPacket.setResultPosition(Vector3i.ZERO); + stopFlyingPacket.setFace(0); + session.sendUpstreamPacket(stopFlyingPacket); + } + } + case STOP_FLYING -> { + session.setFlying(false); + session.sendDownstreamGamePacket(new ServerboundPlayerAbilitiesPacket(false)); + } + case START_GLIDING -> { + // Otherwise gliding will not work in creative + ServerboundPlayerAbilitiesPacket playerAbilitiesPacket = new ServerboundPlayerAbilitiesPacket(false); + session.sendDownstreamGamePacket(playerAbilitiesPacket); + sendPlayerGlideToggle(session, entity); + } + case STOP_GLIDING -> sendPlayerGlideToggle(session, entity); + case MISSED_SWING -> CooldownUtils.sendCooldown(session); // Java edition sends a cooldown when hitting air. + } + } + if (entity.getVehicle() instanceof BoatEntity) { + boolean up = inputData.contains(PlayerAuthInputData.UP); + // Yes. These are flipped. It's always been an issue with Geyser. That's what it's like working with this codebase. + // Hi random stranger. I am six days into updating for 1.21.3. How's it going? + session.setSteeringLeft(up || inputData.contains(PlayerAuthInputData.PADDLE_RIGHT)); + session.setSteeringRight(up || inputData.contains(PlayerAuthInputData.PADDLE_LEFT)); + } + } + + private static void sendPlayerGlideToggle(GeyserSession session, Entity entity) { + ServerboundPlayerCommandPacket glidePacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_ELYTRA_FLYING); + session.sendDownstreamGamePacket(glidePacket); + } + + private static void processItemUseTransaction(GeyserSession session, ItemUseTransaction transaction) { + if (transaction.getActionType() == 2) { + int blockState = session.getGameMode() == GameMode.CREATIVE ? + session.getGeyser().getWorldManager().getBlockAt(session, transaction.getBlockPosition()) : session.getBreakingBlock(); + + session.setLastBlockPlaced(null); + session.setLastBlockPlacePosition(null); + + // Same deal with vanilla block placing as above. + if (!session.getWorldBorder().isInsideBorderBoundaries()) { + BedrockInventoryTransactionTranslator.restoreCorrectBlock(session, transaction.getBlockPosition()); + return; + } + + Vector3f playerPosition = session.getPlayerEntity().getPosition(); + playerPosition = playerPosition.down(EntityDefinitions.PLAYER.offset() - session.getEyeHeight()); + + if (!BedrockInventoryTransactionTranslator.canInteractWithBlock(session, playerPosition, transaction.getBlockPosition())) { + BedrockInventoryTransactionTranslator.restoreCorrectBlock(session, transaction.getBlockPosition()); + return; + } + + int sequence = session.getWorldCache().nextPredictionSequence(); + session.getWorldCache().markPositionInSequence(transaction.getBlockPosition()); + // -1 means we don't know what block they're breaking + if (blockState == -1) { + blockState = Block.JAVA_AIR_ID; + } + + LevelEventPacket blockBreakPacket = new LevelEventPacket(); + blockBreakPacket.setType(LevelEvent.PARTICLE_DESTROY_BLOCK); + blockBreakPacket.setPosition(transaction.getBlockPosition().toFloat()); + blockBreakPacket.setData(session.getBlockMappings().getBedrockBlockId(blockState)); + session.sendUpstreamPacket(blockBreakPacket); + session.setBreakingBlock(-1); + + Entity itemFrameEntity = ItemFrameEntity.getItemFrameEntity(session, transaction.getBlockPosition()); + if (itemFrameEntity != null) { + ServerboundInteractPacket attackPacket = new ServerboundInteractPacket(itemFrameEntity.getEntityId(), + InteractAction.ATTACK, session.isSneaking()); + session.sendDownstreamGamePacket(attackPacket); + return; + } + + PlayerAction action = session.getGameMode() == GameMode.CREATIVE ? PlayerAction.START_DIGGING : PlayerAction.FINISH_DIGGING; + ServerboundPlayerActionPacket breakPacket = new ServerboundPlayerActionPacket(action, transaction.getBlockPosition(), Direction.VALUES[transaction.getBlockFace()], sequence); + session.sendDownstreamGamePacket(breakPacket); + } else { + session.getGeyser().getLogger().error("Unhandled item use transaction type!"); + if (session.getGeyser().getLogger().isDebug()) { + session.getGeyser().getLogger().debug(transaction); + } + } + } + + private static void processVehicleInput(GeyserSession session, PlayerAuthInputPacket packet, boolean wasJumping) { + Entity vehicle = session.getPlayerEntity().getVehicle(); + if (vehicle == null) { + return; + } + if (vehicle instanceof ClientVehicle) { + session.getPlayerEntity().setVehicleInput(packet.getMotion()); + } + + boolean sendMovement = false; + if (vehicle instanceof AbstractHorseEntity && !(vehicle instanceof LlamaEntity)) { + sendMovement = !(vehicle instanceof ClientVehicle); + } else if (vehicle instanceof BoatEntity) { + if (vehicle.getPassengers().size() == 1) { + // The player is the only rider + sendMovement = true; + } else { + // Check if the player is the front rider + if (session.getPlayerEntity().isRidingInFront()) { + sendMovement = true; + } + } + } + + if (vehicle instanceof AbstractHorseEntity) { + // Behavior verified as of Java Edition 1.21.3 + int currentJumpingTicks = session.getInputCache().getJumpingTicks(); + if (currentJumpingTicks < 0) { + session.getInputCache().setJumpingTicks(++currentJumpingTicks); + if (currentJumpingTicks == 0) { + session.getInputCache().setJumpScale(0); + } + } + + boolean holdingJump = packet.getInputData().contains(PlayerAuthInputData.JUMPING); + if (wasJumping && !holdingJump) { + // Jump released + // Yes, I'm fairly certain that entity ID is correct. + int finalVehicleJumpStrength = GenericMath.floor(session.getInputCache().getJumpScale() * 100f); + session.sendDownstreamGamePacket(new ServerboundPlayerCommandPacket(session.getPlayerEntity().getEntityId(), + PlayerState.START_HORSE_JUMP, finalVehicleJumpStrength)); + session.getInputCache().setJumpingTicks(-10); + session.getPlayerEntity().setVehicleJumpStrength(finalVehicleJumpStrength); + } else if (!wasJumping && holdingJump) { + session.getInputCache().setJumpingTicks(0); + session.getInputCache().setJumpScale(0); + } else if (holdingJump) { + session.getInputCache().setJumpingTicks(++currentJumpingTicks); + if (currentJumpingTicks < 10) { + session.getInputCache().setJumpScale(session.getInputCache().getJumpingTicks() * 0.1F); + } else { + session.getInputCache().setJumpScale(0.8f + 2.0f / (currentJumpingTicks - 9) * 0.1f); + } + } + } else { + session.getInputCache().setJumpScale(0); + } + + if (sendMovement) { + Vector3f vehiclePosition = packet.getPosition(); + Vector2f vehicleRotation = packet.getVehicleRotation(); + if (vehicleRotation == null) { + return; // If the client just got in or out of a vehicle for example. + } + + if (session.getWorldBorder().isPassingIntoBorderBoundaries(vehiclePosition, false)) { + Vector3f position = vehicle.getPosition(); + if (vehicle instanceof BoatEntity boat) { + // Undo the changes usually applied to the boat + boat.moveAbsoluteWithoutAdjustments(position, vehicle.getYaw(), vehicle.isOnGround(), true); + } else { + // This doesn't work if teleported is false + vehicle.moveAbsolute(position, + vehicle.getYaw(), vehicle.getPitch(), vehicle.getHeadYaw(), + vehicle.isOnGround(), true); + } + return; + } + + if (vehicle instanceof BoatEntity && !vehicle.isOnGround()) { + // Remove some Y position to prevents boats flying up + vehiclePosition = vehiclePosition.down(vehicle.getDefinition().offset()); + } + + vehicle.setPosition(vehiclePosition); + ServerboundMoveVehiclePacket moveVehiclePacket = new ServerboundMoveVehiclePacket( + vehiclePosition.getX(), vehiclePosition.getY(), vehiclePosition.getZ(), + vehicleRotation.getY() - 90, vehiclePosition.getX() // TODO I wonder if this is related to the horse spinning bugs... + ); + session.sendDownstreamGamePacket(moveVehiclePacket); + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/world/BedrockLevelSoundEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/world/BedrockLevelSoundEventTranslator.java index 7e791ab2d..62b1b8b14 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/world/BedrockLevelSoundEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/world/BedrockLevelSoundEventTranslator.java @@ -89,6 +89,7 @@ public class BedrockLevelSoundEventTranslator extends PacketTranslator { +public class JavaFinishConfigurationTranslator extends PacketTranslator { + /** + * Required to use the specified cartography table recipes + */ + private static final List CARTOGRAPHY_RECIPES = List.of( + MultiRecipeData.of(UUID.fromString("8b36268c-1829-483c-a0f1-993b7156a8f2"), ++LAST_RECIPE_NET_ID), // Map extending + MultiRecipeData.of(UUID.fromString("442d85ed-8272-4543-a6f1-418f90ded05d"), ++LAST_RECIPE_NET_ID), // Map cloning + MultiRecipeData.of(UUID.fromString("98c84b38-1085-46bd-b1ce-dd38c159e6cc"), ++LAST_RECIPE_NET_ID), // Map upgrading + MultiRecipeData.of(UUID.fromString("602234e4-cac1-4353-8bb7-b1ebff70024b"), ++LAST_RECIPE_NET_ID) // Map locking + ); @Override public void translate(GeyserSession session, ClientboundFinishConfigurationPacket packet) { @@ -46,6 +64,26 @@ public class JavaFinishConfigurationPacketTranslator extends PacketTranslator CONFIGURATION + * Triggers protocol change LOGIN -> CONFIGURATION */ -@Translator(packet = ClientboundGameProfilePacket.class) -public class JavaGameProfileTranslator extends PacketTranslator { +@Translator(packet = ClientboundLoginFinishedPacket.class) +public class JavaLoginFinishedTranslator extends PacketTranslator { @Override - public void translate(GeyserSession session, ClientboundGameProfilePacket packet) { + public void translate(GeyserSession session, ClientboundLoginFinishedPacket packet) { PlayerEntity playerEntity = session.getPlayerEntity(); AuthType remoteAuthType = session.remoteServer().authType(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRecipeBookAddTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRecipeBookAddTranslator.java new file mode 100644 index 000000000..05be7db3d --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRecipeBookAddTranslator.java @@ -0,0 +1,335 @@ +/* + * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.translator.protocol.java; + +import com.google.common.collect.Lists; +import it.unimi.dsi.fastutil.Pair; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.kyori.adventure.key.Key; +import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; +import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.RecipeUnlockingRequirement; +import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.ShapedRecipeData; +import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.ShapelessRecipeData; +import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.SmithingTransformRecipeData; +import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.DefaultDescriptor; +import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount; +import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemTagDescriptor; +import org.cloudburstmc.protocol.bedrock.packet.CraftingDataPacket; +import org.cloudburstmc.protocol.bedrock.packet.UnlockedRecipesPacket; +import org.geysermc.geyser.inventory.recipe.GeyserRecipe; +import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe; +import org.geysermc.geyser.inventory.recipe.GeyserShapelessRecipe; +import org.geysermc.geyser.inventory.recipe.GeyserSmithingRecipe; +import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.item.type.BedrockRequiresTagItem; +import org.geysermc.geyser.item.type.Item; +import org.geysermc.geyser.registry.Registries; +import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.registry.JavaRegistries; +import org.geysermc.geyser.session.cache.tags.Tag; +import org.geysermc.geyser.translator.item.ItemTranslator; +import org.geysermc.geyser.translator.protocol.PacketTranslator; +import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.RecipeDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.RecipeDisplayEntry; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.ShapedCraftingRecipeDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.ShapelessCraftingRecipeDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.SmithingRecipeDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.CompositeSlotDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.EmptySlotDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.ItemSlotDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.ItemStackSlotDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.SlotDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.SmithingTrimDemoSlotDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.TagSlotDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.WithRemainderSlotDisplay; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundRecipeBookAddPacket; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; + +@Translator(packet = ClientboundRecipeBookAddPacket.class) +public class JavaRecipeBookAddTranslator extends PacketTranslator { + + @Override + public void translate(GeyserSession session, ClientboundRecipeBookAddPacket packet) { + int netId = session.getLastRecipeNetId().get(); + Int2ObjectMap> javaToBedrockRecipeIds = session.getJavaToBedrockRecipeIds(); + Int2ObjectMap geyserRecipes = session.getCraftingRecipes(); + CraftingDataPacket craftingDataPacket = new CraftingDataPacket(); + + UnlockedRecipesPacket recipesPacket = new UnlockedRecipesPacket(); + recipesPacket.setAction(packet.isReplace() ? UnlockedRecipesPacket.ActionType.INITIALLY_UNLOCKED : UnlockedRecipesPacket.ActionType.NEWLY_UNLOCKED); + + for (ClientboundRecipeBookAddPacket.Entry entry : packet.getEntries()) { + RecipeDisplayEntry contents = entry.contents(); + RecipeDisplay display = contents.display(); + + switch (display.getType()) { + case CRAFTING_SHAPED -> { + ShapedCraftingRecipeDisplay shapedRecipe = (ShapedCraftingRecipeDisplay) display; + var bedrockRecipes = combinations(session, display, shapedRecipe.ingredients()); + if (bedrockRecipes == null) { + continue; + } + List bedrockRecipeIds = new ArrayList<>(); + ItemData output = bedrockRecipes.right(); + List> left = bedrockRecipes.left(); + GeyserRecipe geyserRecipe = new GeyserShapedRecipe(shapedRecipe); + for (int i = 0; i < left.size(); i++) { + List inputs = left.get(i); + String recipeId = contents.id() + "_" + i; + int recipeNetworkId = netId++; + craftingDataPacket.getCraftingData().add(ShapedRecipeData.shaped(recipeId, + shapedRecipe.width(), shapedRecipe.height(), inputs, + Collections.singletonList(output), UUID.randomUUID(), "crafting_table", 0, recipeNetworkId, false, RecipeUnlockingRequirement.INVALID)); + recipesPacket.getUnlockedRecipes().add(recipeId); + bedrockRecipeIds.add(recipeId); + geyserRecipes.put(recipeNetworkId, geyserRecipe); + } + javaToBedrockRecipeIds.put(contents.id(), List.copyOf(bedrockRecipeIds)); + } + case CRAFTING_SHAPELESS -> { + ShapelessCraftingRecipeDisplay shapelessRecipe = (ShapelessCraftingRecipeDisplay) display; + var bedrockRecipes = combinations(session, display, shapelessRecipe.ingredients()); + if (bedrockRecipes == null) { + continue; + } + List bedrockRecipeIds = new ArrayList<>(); + ItemData output = bedrockRecipes.right(); + List> left = bedrockRecipes.left(); + GeyserRecipe geyserRecipe = new GeyserShapelessRecipe(shapelessRecipe); + for (int i = 0; i < left.size(); i++) { + List inputs = left.get(i); + String recipeId = contents.id() + "_" + i; + int recipeNetworkId = netId++; + craftingDataPacket.getCraftingData().add(ShapelessRecipeData.shapeless(recipeId, + inputs, Collections.singletonList(output), UUID.randomUUID(), "crafting_table", 0, recipeNetworkId, RecipeUnlockingRequirement.INVALID)); + recipesPacket.getUnlockedRecipes().add(recipeId); + bedrockRecipeIds.add(recipeId); + geyserRecipes.put(recipeNetworkId, geyserRecipe); + } + javaToBedrockRecipeIds.put(contents.id(), List.copyOf(bedrockRecipeIds)); + } + case SMITHING -> { + if (display.result() instanceof SmithingTrimDemoSlotDisplay) { + // Skip these - Bedrock already knows about them from the TrimDataPacket + continue; + } + SmithingRecipeDisplay smithingRecipe = (SmithingRecipeDisplay) display; + Pair output = translateToOutput(session, smithingRecipe.result()); + if (output == null) { + continue; + } + + List bases = translateToInput(session, smithingRecipe.base()); + List templates = translateToInput(session, smithingRecipe.template()); + List additions = translateToInput(session, smithingRecipe.addition()); + + if (bases == null || templates == null || additions == null) { + continue; + } + + int i = 0; + List bedrockRecipeIds = new ArrayList<>(); + for (ItemDescriptorWithCount template : templates) { + for (ItemDescriptorWithCount base : bases) { + for (ItemDescriptorWithCount addition : additions) { + String id = contents.id() + "_" + i++; + // Note: vanilla inputs use aux value of Short.MAX_VALUE + craftingDataPacket.getCraftingData().add(SmithingTransformRecipeData.of(id, + template, base, addition, output.right(), "smithing_table", netId++)); + + recipesPacket.getUnlockedRecipes().add(id); + bedrockRecipeIds.add(id); + } + } + } + javaToBedrockRecipeIds.put(contents.id(), bedrockRecipeIds); + session.getSmithingRecipes().add(new GeyserSmithingRecipe(smithingRecipe)); + } + } + } + + session.sendUpstreamPacket(craftingDataPacket); + session.sendUpstreamPacket(recipesPacket); + session.getLastRecipeNetId().set(netId); + + // Multi-version can mean different Bedrock item IDs + TAG_TO_ITEM_DESCRIPTOR_CACHE.remove(); + } + + // Arrays are usually an issue in maps, but because it's referencing the tag array that is unchanged, it actually works out for us. + private static final ThreadLocal>> TAG_TO_ITEM_DESCRIPTOR_CACHE = ThreadLocal.withInitial(Object2ObjectOpenHashMap::new); + + private List translateToInput(GeyserSession session, SlotDisplay slotDisplay) { + if (slotDisplay instanceof EmptySlotDisplay) { + return Collections.singletonList(ItemDescriptorWithCount.EMPTY); + } + if (slotDisplay instanceof CompositeSlotDisplay composite) { + if (composite.contents().size() == 1) { + return translateToInput(session, composite.contents().get(0)); + } + return composite.contents().stream() + .map(subDisplay -> translateToInput(session, subDisplay)) + .filter(Objects::nonNull) + .flatMap(List::stream) + .toList(); + } + if (slotDisplay instanceof WithRemainderSlotDisplay remainder) { + // Don't need to worry about what will stay in the crafting table after crafting for the purposes of sending recipes to Bedrock + return translateToInput(session, remainder.input()); + } + if (slotDisplay instanceof ItemSlotDisplay itemSlot) { + return Collections.singletonList(fromItem(session, itemSlot.item())); + } + if (slotDisplay instanceof ItemStackSlotDisplay itemStackSlot) { + ItemData item = ItemTranslator.translateToBedrock(session, itemStackSlot.itemStack()); + return Collections.singletonList(ItemDescriptorWithCount.fromItem(item)); + } + if (slotDisplay instanceof TagSlotDisplay tagSlot) { + Key tag = tagSlot.tag(); + int[] items = session.getTagCache().getRaw(new Tag<>(JavaRegistries.ITEM, tag)); // I don't like this... + if (items == null || items.length == 0) { + return Collections.singletonList(ItemDescriptorWithCount.EMPTY); + } else if (items.length == 1) { + return Collections.singletonList(fromItem(session, items[0])); + } else { + // Cache is implemented as, presumably, an item tag will be used multiple times in succession + // (E.G. a chest with planks tags) + return TAG_TO_ITEM_DESCRIPTOR_CACHE.get().computeIfAbsent(items, key -> { + var bedrockTags = Registries.TAGS.forVersion(session.getUpstream().getProtocolVersion()); + String bedrockTag = bedrockTags.get(key); + if (bedrockTag != null) { + return Collections.singletonList( + new ItemDescriptorWithCount(new ItemTagDescriptor(bedrockTag), 1) + ); + } + + // In the future, we can probably search through and use subsets of tags as well. + // I.E. if a Bedrock tag contains [stone stone_brick] and the Java tag uses [stone stone_brick bricks] + // we can still use that Bedrock tag alongside plain item descriptors for "bricks". + + Set itemDescriptors = new HashSet<>(); + for (int item : key) { + itemDescriptors.add(fromItem(session, item)); + } + return List.copyOf(itemDescriptors); // This, or a list from the start with contains -> add? + }); + } + } + session.getGeyser().getLogger().warning("Unimplemented slot display type for input: " + slotDisplay); + return null; + } + + private Pair translateToOutput(GeyserSession session, SlotDisplay slotDisplay) { + if (slotDisplay instanceof EmptySlotDisplay) { + return null; + } + if (slotDisplay instanceof ItemSlotDisplay itemSlot) { + int item = itemSlot.item(); + return Pair.of(Registries.JAVA_ITEMS.get(item), ItemTranslator.translateToBedrock(session, new ItemStack(item))); + } + if (slotDisplay instanceof ItemStackSlotDisplay itemStackSlot) { + ItemStack stack = itemStackSlot.itemStack(); + return Pair.of(Registries.JAVA_ITEMS.get(stack.getId()), ItemTranslator.translateToBedrock(session, stack)); + } + session.getGeyser().getLogger().warning("Unimplemented slot display type for output: " + slotDisplay); + return null; + } + + private ItemDescriptorWithCount fromItem(GeyserSession session, int item) { + if (item == Items.AIR_ID) { + return ItemDescriptorWithCount.EMPTY; + } + ItemMapping mapping = session.getItemMappings().getMapping(item); + return new ItemDescriptorWithCount(new DefaultDescriptor(mapping.getBedrockDefinition(), mapping.getBedrockData()), 1); // Need to check count + } + + private Pair>, ItemData> combinations(GeyserSession session, RecipeDisplay display, List ingredients) { + Pair pair = translateToOutput(session, display.result()); + if (pair == null || !pair.right().isValid()) { + // Likely modded item Bedrock will complain about + // Implementation note: ItemData#isValid() may return true for air because count might be > 0 and the air definition may not be ItemDefinition.AIR + return null; + } + + ItemData output = pair.right(); + if (!(pair.left() instanceof BedrockRequiresTagItem)) { + // Strip NBT - tools won't appear in the recipe book otherwise + output = output.toBuilder().tag(null).build(); + } + + boolean empty = true; + boolean complexInputs = false; + List> inputs = new ArrayList<>(ingredients.size()); + for (SlotDisplay input : ingredients) { + List translated = translateToInput(session, input); + if (translated == null) { + continue; + } + inputs.add(translated); + if (translated.size() != 1 || translated.get(0) != ItemDescriptorWithCount.EMPTY) { + empty = false; + } + complexInputs |= translated.size() > 1; + } + if (empty) { + // Crashes Bedrock 1.19.70 otherwise + // Fixes https://github.com/GeyserMC/Geyser/issues/3549 + return null; + } + + if (complexInputs) { + long size = 1; + // See how big a cartesian product will get without creating one (Guava throws an error; not really ideal) + for (List list : inputs) { + size *= list.size(); + if (size > 500) { + // Too much. No. + complexInputs = false; + break; + } + } + if (complexInputs) { + return Pair.of(Lists.cartesianProduct(inputs), output); + } + } + return Pair.of( + Collections.singletonList(inputs.stream().map(descriptors -> descriptors.get(0)).toList()), + output + ); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaClientboundRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRecipeBookRemoveTranslator.java similarity index 59% rename from core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaClientboundRecipesTranslator.java rename to core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRecipeBookRemoveTranslator.java index 9eb69183d..27faecef7 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaClientboundRecipesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRecipeBookRemoveTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org + * Copyright (c) 2024 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,51 +25,34 @@ package org.geysermc.geyser.translator.protocol.java; -import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundRecipePacket; import org.cloudburstmc.protocol.bedrock.packet.UnlockedRecipesPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundRecipeBookRemovePacket; import java.util.ArrayList; import java.util.List; -@Translator(packet = ClientboundRecipePacket.class) -public class JavaClientboundRecipesTranslator extends PacketTranslator { +@Translator(packet = ClientboundRecipeBookRemovePacket.class) +public class JavaRecipeBookRemoveTranslator extends PacketTranslator { @Override - public void translate(GeyserSession session, ClientboundRecipePacket packet) { - UnlockedRecipesPacket recipesPacket = new UnlockedRecipesPacket(); - switch (packet.getAction()) { - case INIT -> { - recipesPacket.setAction(UnlockedRecipesPacket.ActionType.INITIALLY_UNLOCKED); - recipesPacket.getUnlockedRecipes().addAll(getBedrockRecipes(session, packet.getAlreadyKnownRecipes())); - } - case ADD -> { - List recipes = getBedrockRecipes(session, packet.getRecipes()); - if (recipes.isEmpty()) { - // Sending an empty list here packet will crash the client as of 1.20.60 - return; - } - recipesPacket.setAction(UnlockedRecipesPacket.ActionType.NEWLY_UNLOCKED); - recipesPacket.getUnlockedRecipes().addAll(recipes); - } - case REMOVE -> { - List recipes = getBedrockRecipes(session, packet.getRecipes()); - if (recipes.isEmpty()) { - // Sending an empty list here will crash the client as of 1.20.60 - return; - } - recipesPacket.setAction(UnlockedRecipesPacket.ActionType.REMOVE_UNLOCKED); - recipesPacket.getUnlockedRecipes().addAll(recipes); - } + public void translate(GeyserSession session, ClientboundRecipeBookRemovePacket packet) { + List recipes = getBedrockRecipes(session, packet.getRecipes()); + if (recipes.isEmpty()) { + // Sending an empty list here will crash the client as of 1.20.60 + return; } + UnlockedRecipesPacket recipesPacket = new UnlockedRecipesPacket(); + recipesPacket.setAction(UnlockedRecipesPacket.ActionType.REMOVE_UNLOCKED); + recipesPacket.getUnlockedRecipes().addAll(recipes); session.sendUpstreamPacket(recipesPacket); } - private List getBedrockRecipes(GeyserSession session, String[] javaRecipeIdentifiers) { + private List getBedrockRecipes(GeyserSession session, int[] javaRecipeIds) { List recipes = new ArrayList<>(); - for (String javaIdentifier : javaRecipeIdentifiers) { + for (int javaIdentifier : javaRecipeIds) { List bedrockRecipes = session.getJavaToBedrockRecipeIds().get(javaIdentifier); // Some recipes are not (un)lockable on Bedrock edition, like furnace or stonecutter recipes. // So we don't store/send these. @@ -79,4 +62,4 @@ public class JavaClientboundRecipesTranslator extends PacketTranslator { // todo: dump from client? - private static final Set KNOWN_PACK_IDS = Set.of("core", "update_1_21", "bundle", "trade_rebalance"); + private static final Set KNOWN_PACK_IDS = Set.of("core", "winter_drop", "trade_rebalance", "redstone_experiments", "minecart_improvements"); @Override public void translate(GeyserSession session, ClientboundSelectKnownPacks packet) { @@ -62,6 +62,7 @@ public class JavaSelectKnownPacksTranslator extends PacketTranslator { - /** - * Required to use the specified cartography table recipes - */ - private static final List CARTOGRAPHY_RECIPES = List.of( - MultiRecipeData.of(UUID.fromString("8b36268c-1829-483c-a0f1-993b7156a8f2"), ++LAST_RECIPE_NET_ID), // Map extending - MultiRecipeData.of(UUID.fromString("442d85ed-8272-4543-a6f1-418f90ded05d"), ++LAST_RECIPE_NET_ID), // Map cloning - MultiRecipeData.of(UUID.fromString("98c84b38-1085-46bd-b1ce-dd38c159e6cc"), ++LAST_RECIPE_NET_ID), // Map upgrading - MultiRecipeData.of(UUID.fromString("602234e4-cac1-4353-8bb7-b1ebff70024b"), ++LAST_RECIPE_NET_ID) // Map locking - ); private static final List NETHERITE_UPGRADES = List.of( "minecraft:netherite_sword", @@ -112,182 +83,26 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator RECIPE_TAGS = Map.of( - "minecraft:wood", "minecraft:logs", - "minecraft:wooden_slab", "minecraft:wooden_slabs", - "minecraft:planks", "minecraft:planks"); + private static final Key SMITHING_BASE = MinecraftKey.key("smithing_base"); + private static final Key SMITHING_TEMPLATE = MinecraftKey.key("smithing_template"); + private static final Key SMITHING_ADDITION = MinecraftKey.key("smithing_addition"); @Override public void translate(GeyserSession session, ClientboundUpdateRecipesPacket packet) { - boolean sendTrimRecipes = false; - Map> recipeIDs = session.getJavaToBedrockRecipeIds(); - recipeIDs.clear(); - Int2ObjectMap recipeMap = new Int2ObjectOpenHashMap<>(); - Int2ObjectMap> unsortedStonecutterData = new Int2ObjectOpenHashMap<>(); + int netId = session.getLastRecipeNetId().get(); CraftingDataPacket craftingDataPacket = new CraftingDataPacket(); - craftingDataPacket.setCleanRecipes(true); - RecipeContext context = new RecipeContext(session, craftingDataPacket, recipeMap); - - for (Recipe recipe : packet.getRecipes()) { - switch (recipe.getType()) { - case CRAFTING_SHAPELESS -> { - ShapelessRecipeData shapelessRecipeData = (ShapelessRecipeData) recipe.getData(); - List bedrockRecipeIDs = context.translateShapelessRecipe(new GeyserShapelessRecipe(shapelessRecipeData)); - if (bedrockRecipeIDs != null) { - context.addRecipeIdentifier(session, recipe.getIdentifier().asString(), bedrockRecipeIDs); - } - } - case CRAFTING_SHAPED -> { - ShapedRecipeData shapedRecipeData = (ShapedRecipeData) recipe.getData(); - List bedrockRecipeIDs = context.translateShapedRecipe(new GeyserShapedRecipe(shapedRecipeData)); - if (bedrockRecipeIDs != null) { - context.addRecipeIdentifier(session, recipe.getIdentifier().asString(), bedrockRecipeIDs); - } - } - case STONECUTTING -> { - StoneCuttingRecipeData stoneCuttingData = (StoneCuttingRecipeData) recipe.getData(); - if (stoneCuttingData.getIngredient().getOptions().length == 0) { - if (GeyserImpl.getInstance().getConfig().isDebugMode()) { - GeyserImpl.getInstance().getLogger().debug("Received broken stone cutter recipe: " + stoneCuttingData + " " + - recipe.getIdentifier() + " " + Registries.JAVA_ITEMS.get().get(stoneCuttingData.getResult().getId()).javaIdentifier()); - } - continue; - } - ItemStack ingredient = stoneCuttingData.getIngredient().getOptions()[0]; - List data = unsortedStonecutterData.get(ingredient.getId()); - if (data == null) { - data = new ArrayList<>(); - unsortedStonecutterData.put(ingredient.getId(), data); - } - // Save for processing after all recipes have been received - data.add(stoneCuttingData); - } - case SMITHING_TRANSFORM -> { - SmithingTransformRecipeData data = (SmithingTransformRecipeData) recipe.getData(); - ItemData output = ItemTranslator.translateToBedrock(session, data.getResult()); - - for (ItemStack template : data.getTemplate().getOptions()) { - ItemDescriptorWithCount bedrockTemplate = ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, template)); - - for (ItemStack base : data.getBase().getOptions()) { - ItemDescriptorWithCount bedrockBase = ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, base)); - - for (ItemStack addition : data.getAddition().getOptions()) { - ItemDescriptorWithCount bedrockAddition = ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, addition)); - - String id = recipe.getIdentifier().asString(); - // Note: vanilla inputs use aux value of Short.MAX_VALUE - craftingDataPacket.getCraftingData().add(org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.SmithingTransformRecipeData.of(id, - bedrockTemplate, bedrockBase, bedrockAddition, output, "smithing_table", context.getAndIncrementNetId())); - - recipeIDs.put(id, new ArrayList<>(Collections.singletonList(id))); - } - } - } - } - case SMITHING_TRIM -> { - sendTrimRecipes = true; - // ignored currently - see below - } - case CRAFTING_DECORATED_POT -> { - // Paper 1.20 seems to send only one recipe, which seems to be hardcoded to include all recipes. - // We can send the equivalent Bedrock MultiRecipe! :) - craftingDataPacket.getCraftingData().add(MultiRecipeData.of(UUID.fromString("685a742a-c42e-4a4e-88ea-5eb83fc98e5b"), context.getAndIncrementNetId())); - } - case CRAFTING_SPECIAL_BOOKCLONING -> { - craftingDataPacket.getCraftingData().add(MultiRecipeData.of(UUID.fromString("d1ca6b84-338e-4f2f-9c6b-76cc8b4bd98d"), context.getAndIncrementNetId())); - } - case CRAFTING_SPECIAL_REPAIRITEM -> { - craftingDataPacket.getCraftingData().add(MultiRecipeData.of(UUID.fromString("00000000-0000-0000-0000-000000000001"), context.getAndIncrementNetId())); - } - case CRAFTING_SPECIAL_MAPEXTENDING -> { - craftingDataPacket.getCraftingData().add(MultiRecipeData.of(UUID.fromString("d392b075-4ba1-40ae-8789-af868d56f6ce"), context.getAndIncrementNetId())); - } - case CRAFTING_SPECIAL_MAPCLONING -> { - craftingDataPacket.getCraftingData().add(MultiRecipeData.of(UUID.fromString("85939755-ba10-4d9d-a4cc-efb7a8e943c4"), context.getAndIncrementNetId())); - } - case CRAFTING_SPECIAL_FIREWORK_ROCKET -> { - craftingDataPacket.getCraftingData().add(MultiRecipeData.of(UUID.fromString("00000000-0000-0000-0000-000000000002"), context.getAndIncrementNetId())); - } - default -> { - List recipes = Registries.RECIPES.get(recipe.getType()); - if (recipes != null) { - List bedrockRecipeIds = new ArrayList<>(); - if (recipe.getType() == RecipeType.CRAFTING_SPECIAL_TIPPEDARROW) { - // Only shaped recipe at this moment - for (GeyserRecipe builtInRecipe : recipes) { - var recipeIds = context.translateShapedRecipe((GeyserShapedRecipe) builtInRecipe); - if (recipeIds != null) { - bedrockRecipeIds.addAll(recipeIds); - } - } - } else if (recipe.getType() == RecipeType.CRAFTING_SPECIAL_SHULKERBOXCOLORING) { - for (GeyserRecipe builtInRecipe : recipes) { - var recipeIds = context.translateShulkerBoxRecipe((GeyserShapelessRecipe) builtInRecipe); - if (recipeIds != null) { - bedrockRecipeIds.addAll(recipeIds); - } - } - } else { - for (GeyserRecipe builtInRecipe : recipes) { - var recipeIds = context.translateShapelessRecipe((GeyserShapelessRecipe) builtInRecipe); - if (recipeIds != null) { - bedrockRecipeIds.addAll(recipeIds); - } - } - } - context.addSpecialRecipesIdentifiers(recipe, bedrockRecipeIds); - } - } - } - } - craftingDataPacket.getCraftingData().addAll(CARTOGRAPHY_RECIPES); - craftingDataPacket.getPotionMixData().addAll(Registries.POTION_MIXES.forVersion(session.getUpstream().getProtocolVersion())); - - Int2ObjectMap stonecutterRecipeMap = new Int2ObjectOpenHashMap<>(); - for (Int2ObjectMap.Entry> data : unsortedStonecutterData.int2ObjectEntrySet()) { - // Sort the list by each output item's Java identifier - this is how it's sorted on Java, and therefore - // We can get the correct order for button pressing - data.getValue().sort(Comparator.comparing((stoneCuttingRecipeData -> - Registries.JAVA_ITEMS.get().get(stoneCuttingRecipeData.getResult().getId()) - // See RecipeManager#getRecipesFor as of 1.21 - .translationKey()))); - - // Now that it's sorted, let's translate these recipes - int buttonId = 0; - for (StoneCuttingRecipeData stoneCuttingData : data.getValue()) { - // As of 1.16.4, all stonecutter recipes have one ingredient option - ItemStack ingredient = stoneCuttingData.getIngredient().getOptions()[0]; - ItemData input = ItemTranslator.translateToBedrock(session, ingredient); - ItemDescriptorWithCount descriptor = ItemDescriptorWithCount.fromItem(input); - ItemStack javaOutput = stoneCuttingData.getResult(); - ItemData output = ItemTranslator.translateToBedrock(session, javaOutput); - if (!input.isValid() || !output.isValid()) { - // Probably modded items - continue; - } - UUID uuid = UUID.randomUUID(); - // We need to register stonecutting recipes, so they show up on Bedrock - craftingDataPacket.getCraftingData().add(org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.ShapelessRecipeData.shapeless(uuid.toString(), - Collections.singletonList(descriptor), Collections.singletonList(output), uuid, "stonecutter", 0, context.netId, RecipeUnlockingRequirement.INVALID)); - - // Save the recipe list for reference when crafting - // Add the net ID as the key and the button required + output for the value - stonecutterRecipeMap.put(context.getAndIncrementNetId(), new GeyserStonecutterData(buttonId++, javaOutput)); - - // Currently, stone cutter recipes are not locked/unlocked on Bedrock; so no need to cache their identifiers. - } - } - - session.getLastRecipeNetId().set(context.netId); // No increment - - // Only send smithing trim recipes if Java/ViaVersion sends them. - if (sendTrimRecipes) { + boolean oldSmithingTable; + int[] smithingBase = packet.getItemSets().get(SMITHING_BASE); + int[] smithingTemplate = packet.getItemSets().get(SMITHING_TEMPLATE); + int[] smithingAddition = packet.getItemSets().get(SMITHING_ADDITION); + if (smithingBase == null || smithingTemplate == null || smithingAddition == null) { + // We're probably on a version before the smithing table got expanded functionality. + oldSmithingTable = true; + addSmithingTransformRecipes(session, craftingDataPacket.getCraftingData()); + netId = session.getLastRecipeNetId().get(); // Was updated in the above method. + } else { + oldSmithingTable = false; // BDS sends armor trim templates and materials before the CraftingDataPacket TrimDataPacket trimDataPacket = new TrimDataPacket(); trimDataPacket.getPatterns().addAll(session.getRegistryCache().trimPatterns().values()); @@ -297,114 +112,80 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator, IntSet> squashedOptions = new HashMap<>(); - for (int i = 0; i < ingredients.length; i++) { - if (ingredients[i].getOptions().length == 0) { - squashedOptions.computeIfAbsent(Collections.singleton(ItemDescriptorWithCount.EMPTY), k -> new IntOpenHashSet()).add(i); + Int2ObjectMap> unsortedStonecutterData = new Int2ObjectOpenHashMap<>(); + + List stonecutterRecipes = packet.getStonecutterRecipes(); + for (SelectableRecipe recipe : stonecutterRecipes) { + // Hardcoding the heck out of this until we see different examples of how this works. + HolderSet ingredient = recipe.input().getValues(); + if (ingredient.getHolders() == null || ingredient.getHolders().length != 1) { + session.getGeyser().getLogger().debug("Ignoring stonecutter recipe for weird input: " + recipe); continue; } - empty = false; - Ingredient ingredient = ingredients[i]; - Map> groupedByIds = Arrays.stream(ingredient.getOptions()) - .map(item -> ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, item))) - .collect(Collectors.groupingBy(item -> item == ItemDescriptorWithCount.EMPTY ? new GroupedItem(ItemDefinition.AIR, 0) : new GroupedItem(((DefaultDescriptor) item.getDescriptor()).getItemId(), item.getCount()))); - Set optionSet = new HashSet<>(groupedByIds.size()); - for (Map.Entry> entry : groupedByIds.entrySet()) { - if (entry.getValue().size() > 1) { - GroupedItem groupedItem = entry.getKey(); + if (!(recipe.recipe() instanceof ItemStackSlotDisplay)) { + session.getGeyser().getLogger().debug("Ignoring stonecutter recipe for weird output: " + recipe); + continue; + } + unsortedStonecutterData.computeIfAbsent(ingredient.getHolders()[0], $ -> new ArrayList<>()).add(recipe); + } - String recipeTag = RECIPE_TAGS.get(groupedItem.id.getIdentifier()); - if (recipeTag != null && ingredients.length > 1) { - optionSet.add(new ItemDescriptorWithCount(new ItemTagDescriptor(recipeTag), groupedItem.count)); - continue; - } + Int2ObjectMap stonecutterRecipeMap = new Int2ObjectOpenHashMap<>(); + for (Int2ObjectMap.Entry> data : unsortedStonecutterData.int2ObjectEntrySet()) { + // Sort the list by each output item's Java identifier - this is how it's sorted on Java, and therefore + // We can get the correct order for button pressing + data.getValue().sort(Comparator.comparing((stoneCuttingRecipeData -> + Registries.JAVA_ITEMS.get().get(((ItemStackSlotDisplay) stoneCuttingRecipeData.recipe()).itemStack().getId()) + // See RecipeManager#getRecipesFor as of 1.21 + .translationKey()))); - int idCount = 0; - //not optimal - for (ItemMapping mapping : session.getItemMappings().getItems()) { - if (mapping.getBedrockDefinition() == groupedItem.id) { - idCount++; - } - } - if (entry.getValue().size() < idCount) { - optionSet.addAll(entry.getValue()); - } else { - optionSet.add(groupedItem.id == ItemDefinition.AIR ? ItemDescriptorWithCount.EMPTY : new ItemDescriptorWithCount(new DefaultDescriptor(groupedItem.id, Short.MAX_VALUE), groupedItem.count)); - } - } else { - ItemDescriptorWithCount item = entry.getValue().get(0); - optionSet.add(item); + // Now that it's sorted, let's translate these recipes + int buttonId = 0; + for (SelectableRecipe recipe : data.getValue()) { + // As of 1.16.4, all stonecutter recipes have one ingredient option + HolderSet ingredient = recipe.input().getValues(); + int javaInput = ingredient.getHolders()[0]; + ItemMapping mapping = session.getItemMappings().getMapping(javaInput); + if (mapping.getJavaItem() == Items.AIR) { + // Modded ? + continue; } - } - squashedOptions.computeIfAbsent(optionSet, k -> new IntOpenHashSet()).add(i); - } - if (empty) { - // Crashes Bedrock 1.19.70 otherwise - // Fixes https://github.com/GeyserMC/Geyser/issues/3549 - return null; - } - int totalCombinations = 1; - for (Set optionSet : squashedOptions.keySet()) { - totalCombinations *= optionSet.size(); - } - if (totalCombinations > 500) { - ItemDescriptorWithCount[] translatedItems = new ItemDescriptorWithCount[ingredients.length]; - for (int i = 0; i < ingredients.length; i++) { - if (ingredients[i].getOptions().length > 0) { - translatedItems[i] = ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, ingredients[i].getOptions()[0])); - } else { - translatedItems[i] = ItemDescriptorWithCount.EMPTY; + ItemDescriptorWithCount descriptor = new ItemDescriptorWithCount(new DefaultDescriptor(mapping.getBedrockDefinition(), mapping.getBedrockData()), 1); + ItemStack javaOutput = ((ItemStackSlotDisplay) recipe.recipe()).itemStack(); + ItemData output = ItemTranslator.translateToBedrock(session, javaOutput); + if (!output.isValid()) { + // Probably modded items + continue; } + int recipeNetId = netId++; + UUID uuid = UUID.randomUUID(); + // We need to register stonecutting recipes, so they show up on Bedrock + // (Implementation note: recipe ID creates the order which stonecutting recipes are shown in stonecutter) + craftingDataPacket.getCraftingData().add(ShapelessRecipeData.shapeless("stonecutter_" + javaInput + "_" + buttonId, + Collections.singletonList(descriptor), Collections.singletonList(output), uuid, "stonecutter", 0, recipeNetId, RecipeUnlockingRequirement.INVALID)); + + // Save the recipe list for reference when crafting + // Add the net ID as the key and the button required + output for the value + stonecutterRecipeMap.put(recipeNetId, new GeyserStonecutterData(buttonId++, javaOutput)); + + // Currently, stone cutter recipes are not locked/unlocked on Bedrock; so no need to cache their identifiers. } - return new ItemDescriptorWithCount[][]{translatedItems}; } - List> sortedSets = new ArrayList<>(squashedOptions.keySet()); - sortedSets.sort(Comparator.comparing(Set::size, Comparator.reverseOrder())); - ItemDescriptorWithCount[][] combinations = new ItemDescriptorWithCount[totalCombinations][ingredients.length]; - int x = 1; - for (Set set : sortedSets) { - IntSet slotSet = squashedOptions.get(set); - int i = 0; - for (ItemDescriptorWithCount item : set) { - for (int j = 0; j < totalCombinations / set.size(); j++) { - final int comboIndex = (i * x) + (j % x) + ((j / x) * set.size() * x); - for (IntIterator it = slotSet.iterator(); it.hasNext(); ) { - combinations[comboIndex][it.nextInt()] = item; - } - } - i++; - } - x *= set.size(); - } - return combinations; + + session.sendUpstreamPacket(craftingDataPacket); + session.setStonecutterRecipes(stonecutterRecipeMap); + session.getLastRecipeNetId().set(netId); } - - private List getSmithingTransformRecipes(GeyserSession session) { - List recipes = new ArrayList<>(); + + private void addSmithingTransformRecipes(GeyserSession session, List recipes) { ItemMapping template = session.getItemMappings().getStoredItems().upgradeTemplate(); for (String identifier : NETHERITE_UPGRADES) { - recipes.add(org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.SmithingTransformRecipeData.of(identifier + "_smithing", + recipes.add(SmithingTransformRecipeData.of(identifier + "_smithing", getDescriptorFromId(session, template.getBedrockIdentifier()), getDescriptorFromId(session, identifier.replace("netherite", "diamond")), getDescriptorFromId(session, "minecraft:netherite_ingot"), @@ -412,7 +193,6 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator recipeMap; - // Get the last known network ID (first used for some pregenerated recipes) and increment from there. - private int netId = InventoryUtils.LAST_RECIPE_NET_ID + 1; - - private RecipeContext(GeyserSession session, CraftingDataPacket packet, Int2ObjectMap recipeMap) { - this.session = session; - this.packet = packet; - this.recipeMap = recipeMap; - } - - List translateShulkerBoxRecipe(GeyserShapelessRecipe recipe) { - ItemStack result = recipe.result(); - ItemData output = ItemTranslator.translateToBedrock(session, result); - if (!output.isValid()) { - // Likely modded item that Bedrock will complain about if it persists - return null; - } - - Item javaItem = Registries.JAVA_ITEMS.get(result.getId()); - if (!(javaItem instanceof BedrockRequiresTagItem)) { - // Strip NBT - tools won't appear in the recipe book otherwise - output = output.toBuilder().tag(null).build(); - } - ItemDescriptorWithCount[][] inputCombinations = combinations(session, recipe.ingredients()); - if (inputCombinations == null) { - return null; - } - - List bedrockRecipeIDs = new ArrayList<>(); - for (ItemDescriptorWithCount[] inputs : inputCombinations) { - UUID uuid = UUID.randomUUID(); - bedrockRecipeIDs.add(uuid.toString()); - packet.getCraftingData().add(org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.ShapelessRecipeData.shulkerBox(uuid.toString(), - Arrays.asList(inputs), Collections.singletonList(output), uuid, "crafting_table", 0, netId)); - recipeMap.put(netId++, recipe); - } - return bedrockRecipeIDs; - } - - List translateShapelessRecipe(GeyserShapelessRecipe recipe) { - ItemStack result = recipe.result(); - ItemData output = ItemTranslator.translateToBedrock(session, result); - if (!output.isValid()) { - // Likely modded item that Bedrock will complain about if it persists - return null; - } - - Item javaItem = Registries.JAVA_ITEMS.get(result.getId()); - if (!(javaItem instanceof BedrockRequiresTagItem)) { - // Strip NBT - tools won't appear in the recipe book otherwise - output = output.toBuilder().tag(null).build(); - } - ItemDescriptorWithCount[][] inputCombinations = combinations(session, recipe.ingredients()); - if (inputCombinations == null) { - return null; - } - - List bedrockRecipeIDs = new ArrayList<>(); - for (ItemDescriptorWithCount[] inputs : inputCombinations) { - UUID uuid = UUID.randomUUID(); - bedrockRecipeIDs.add(uuid.toString()); - packet.getCraftingData().add(org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.ShapelessRecipeData.shapeless(uuid.toString(), - Arrays.asList(inputs), Collections.singletonList(output), uuid, "crafting_table", 0, netId, RecipeUnlockingRequirement.INVALID)); - recipeMap.put(netId++, recipe); - } - return bedrockRecipeIDs; - } - - List translateShapedRecipe(GeyserShapedRecipe recipe) { - ItemStack result = recipe.result(); - ItemData output = ItemTranslator.translateToBedrock(session, result); - if (!output.isValid()) { - // Likely modded item that Bedrock will complain about if it persists - return null; - } - - Item javaItem = Registries.JAVA_ITEMS.get(result.getId()); - if (!(javaItem instanceof BedrockRequiresTagItem)) { - // Strip NBT - tools won't appear in the recipe book otherwise - output = output.toBuilder().tag(null).build(); - } - ItemDescriptorWithCount[][] inputCombinations = combinations(session, recipe.ingredients()); - if (inputCombinations == null) { - return null; - } - - List bedrockRecipeIDs = new ArrayList<>(); - for (ItemDescriptorWithCount[] inputs : inputCombinations) { - UUID uuid = UUID.randomUUID(); - bedrockRecipeIDs.add(uuid.toString()); - packet.getCraftingData().add(org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.ShapedRecipeData.shaped(uuid.toString(), - recipe.width(), recipe.height(), Arrays.asList(inputs), - Collections.singletonList(output), uuid, "crafting_table", 0, netId, false, RecipeUnlockingRequirement.INVALID)); - recipeMap.put(netId++, recipe); - } - return bedrockRecipeIDs; - } - - void addSpecialRecipesIdentifiers(Recipe recipe, List identifiers) { - String javaRecipeID = switch (recipe.getType()) { - case CRAFTING_SPECIAL_SHULKERBOXCOLORING -> - // BDS (un)locks the dyeing with the shulker box recipe, Java never - we want BDS behavior for ease of use - "minecraft:shulker_box"; - case CRAFTING_SPECIAL_TIPPEDARROW -> - // similar as above - "minecraft:arrow"; - default -> recipe.getIdentifier().asString(); - }; - - addRecipeIdentifier(session, javaRecipeID, identifiers); - } - - void addRecipeIdentifier(GeyserSession session, String javaIdentifier, List bedrockIdentifiers) { - session.getJavaToBedrockRecipeIds().computeIfAbsent(javaIdentifier, k -> new ArrayList<>()).addAll(bedrockIdentifiers); - } - - int getAndIncrementNetId() { - return this.netId++; - } - } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockRiderJumpTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityPositionSyncTranslator.java similarity index 55% rename from core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockRiderJumpTranslator.java rename to core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityPositionSyncTranslator.java index 17668e000..fd7fa09ca 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockRiderJumpTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityPositionSyncTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * Copyright (c) 2024 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,27 +23,30 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.translator.protocol.bedrock.entity.player; +package org.geysermc.geyser.translator.protocol.java.entity; -import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerState; -import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerCommandPacket; -import org.cloudburstmc.protocol.bedrock.packet.RiderJumpPacket; +import org.cloudburstmc.math.vector.Vector3d; import org.geysermc.geyser.entity.type.Entity; -import org.geysermc.geyser.entity.type.living.animal.horse.AbstractHorseEntity; +import org.geysermc.geyser.entity.vehicle.ClientVehicle; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundEntityPositionSyncPacket; + +@Translator(packet = ClientboundEntityPositionSyncPacket.class) +public class JavaEntityPositionSyncTranslator extends PacketTranslator { -@Translator(packet = RiderJumpPacket.class) -public class BedrockRiderJumpTranslator extends PacketTranslator { @Override - public void translate(GeyserSession session, RiderJumpPacket packet) { - session.getPlayerEntity().setVehicleJumpStrength(packet.getJumpStrength()); + public void translate(GeyserSession session, ClientboundEntityPositionSyncPacket packet) { + Entity entity = session.getEntityCache().getEntityByJavaId(packet.getId()); + if (entity == null) return; - Entity vehicle = session.getPlayerEntity().getVehicle(); - if (vehicle instanceof AbstractHorseEntity) { - ServerboundPlayerCommandPacket playerCommandPacket = new ServerboundPlayerCommandPacket(vehicle.getEntityId(), PlayerState.START_HORSE_JUMP, packet.getJumpStrength()); - session.sendDownstreamGamePacket(playerCommandPacket); + Vector3d pos = packet.getPosition(); + + if (entity instanceof ClientVehicle clientVehicle) { + clientVehicle.getVehicleComponent().moveAbsolute(pos.getX(), pos.getY(), pos.getZ()); } + + entity.teleport(pos.toFloat(), packet.getYRot(), packet.getXRot(), packet.isOnGround()); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaTeleportEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaTeleportEntityTranslator.java index 47c61eb8e..eda195a8f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaTeleportEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaTeleportEntityTranslator.java @@ -25,26 +25,16 @@ package org.geysermc.geyser.translator.protocol.java.entity; -import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundTeleportEntityPacket; -import org.cloudburstmc.math.vector.Vector3f; -import org.geysermc.geyser.entity.type.Entity; -import org.geysermc.geyser.entity.vehicle.ClientVehicle; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundTeleportEntityPacket; @Translator(packet = ClientboundTeleportEntityPacket.class) public class JavaTeleportEntityTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, ClientboundTeleportEntityPacket packet) { - Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId()); - if (entity == null) return; - - if (entity instanceof ClientVehicle clientVehicle) { - clientVehicle.getVehicleComponent().moveAbsolute(packet.getX(), packet.getY(), packet.getZ()); - } - - entity.teleport(Vector3f.from(packet.getX(), packet.getY(), packet.getZ()), packet.getYaw(), packet.getPitch(), packet.isOnGround()); + session.getGeyser().getLogger().info(packet.toString()); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaCookieRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaCookieRequestTranslator.java index 33bfa7be8..a44faed29 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaCookieRequestTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaCookieRequestTranslator.java @@ -38,7 +38,7 @@ public class JavaCookieRequestTranslator extends PacketTranslator { @@ -50,14 +51,15 @@ public class JavaPlayerPositionTranslator extends PacketTranslator 32 && !session.isEmulatePost1_13Logic()) { // See DimensionUtils for an explanation @@ -92,23 +100,23 @@ public class JavaPlayerPositionTranslator extends PacketTranslator { + + @Override + public void translate(GeyserSession session, ClientboundPlayerRotationPacket packet) { + session.getPlayerEntity().updateOwnRotation(packet.getYRot(), packet.getXRot(), packet.getYRot()); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaSetCarriedItemTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaSetHeldSlotTranslator.java similarity index 86% rename from core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaSetCarriedItemTranslator.java rename to core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaSetHeldSlotTranslator.java index e590b5658..a02aa61ee 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaSetCarriedItemTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaSetHeldSlotTranslator.java @@ -25,17 +25,17 @@ package org.geysermc.geyser.translator.protocol.java.entity.player; -import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.player.ClientboundSetCarriedItemPacket; import org.cloudburstmc.protocol.bedrock.packet.PlayerHotbarPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.player.ClientboundSetHeldSlotPacket; -@Translator(packet = ClientboundSetCarriedItemPacket.class) -public class JavaSetCarriedItemTranslator extends PacketTranslator { +@Translator(packet = ClientboundSetHeldSlotPacket.class) +public class JavaSetHeldSlotTranslator extends PacketTranslator { @Override - public void translate(GeyserSession session, ClientboundSetCarriedItemPacket packet) { + public void translate(GeyserSession session, ClientboundSetHeldSlotPacket packet) { PlayerHotbarPacket hotbarPacket = new PlayerHotbarPacket(); hotbarPacket.setContainerId(0); hotbarPacket.setSelectedHotbarSlot(packet.getSlot()); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetSlotTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetSlotTranslator.java index 2ff2470e7..fa2e3a544 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetSlotTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetSlotTranslator.java @@ -29,6 +29,7 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.RecipeUnlockingRequirement; import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.ShapedRecipeData; +import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.SmithingTransformRecipeData; import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount; import org.cloudburstmc.protocol.bedrock.packet.CraftingDataPacket; import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket; @@ -36,19 +37,25 @@ import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe; +import org.geysermc.geyser.inventory.recipe.GeyserSmithingRecipe; +import org.geysermc.geyser.item.Items; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.translator.inventory.PlayerInventoryTranslator; +import org.geysermc.geyser.translator.inventory.SmithingInventoryTranslator; import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.util.InventoryUtils; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; -import org.geysermc.mcprotocollib.protocol.data.game.recipe.Ingredient; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.ItemStackSlotDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.SlotDisplay; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundContainerSetSlotPacket; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.List; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -57,14 +64,8 @@ public class JavaContainerSetSlotTranslator extends PacketTranslator { + session.setContainerOutputFuture(session.scheduleInEventLoop(() -> { int offset = gridSize == 4 ? 28 : 32; int gridDimensions = gridSize == 4 ? 2 : 3; int firstRow = -1, height = -1; @@ -167,14 +173,13 @@ public class JavaContainerSetSlotTranslator extends PacketTranslator javaIngredients = new ArrayList<>(height * width); int index = 0; for (int row = firstRow; row < height + firstRow; row++) { for (int col = firstCol; col < width + firstCol; col++) { GeyserItemStack geyserItemStack = inventory.getItem(col + (row * gridDimensions) + 1); ingredients[index] = geyserItemStack.getItemData(session); - ItemStack[] itemStacks = new ItemStack[] {geyserItemStack.isEmpty() ? null : geyserItemStack.getItemStack(1)}; - javaIngredients[index] = new Ingredient(itemStacks); + javaIngredients.add(geyserItemStack.asSlotDisplay()); InventorySlotPacket slotPacket = new InventorySlotPacket(); slotPacket.setContainerId(ContainerId.UI); @@ -186,7 +191,7 @@ public class JavaContainerSetSlotTranslator extends PacketTranslator { + GeyserItemStack template = inventory.getItem(SmithingInventoryTranslator.TEMPLATE); + if (template.asItem() != Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE) { + // Technically we should probably also do this for custom items, but last I checked Bedrock doesn't even support that. + return; + } + + GeyserItemStack input = inventory.getItem(SmithingInventoryTranslator.INPUT); + GeyserItemStack material = inventory.getItem(SmithingInventoryTranslator.MATERIAL); + GeyserItemStack geyserOutput = GeyserItemStack.from(output); + + for (GeyserSmithingRecipe recipe : session.getSmithingRecipes()) { + if (InventoryUtils.acceptsAsInput(session, recipe.result(), geyserOutput) + && InventoryUtils.acceptsAsInput(session, recipe.base(), input) + && InventoryUtils.acceptsAsInput(session, recipe.addition(), material) + && InventoryUtils.acceptsAsInput(session, recipe.template(), template)) { + // The client already recognizes this item. + return; + } + } + + session.getSmithingRecipes().add(new GeyserSmithingRecipe( + template.asSlotDisplay(), + input.asSlotDisplay(), + material.asSlotDisplay(), + new ItemStackSlotDisplay(output) + )); + + UUID uuid = UUID.randomUUID(); + + CraftingDataPacket craftPacket = new CraftingDataPacket(); + craftPacket.getCraftingData().add(SmithingTransformRecipeData.of( + uuid.toString(), + ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, template.getItemStack())), + ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, input.getItemStack())), + ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, material.getItemStack())), + ItemTranslator.translateToBedrock(session, output), + "smithing_table", + session.getLastRecipeNetId().incrementAndGet() + )); + craftPacket.setCleanRecipes(false); + session.sendUpstreamPacket(craftPacket); + + // Just set one of the slots to air, then right back to its proper item. + InventorySlotPacket slotPacket = new InventorySlotPacket(); + slotPacket.setContainerId(ContainerId.UI); + slotPacket.setSlot(session.getInventoryTranslator().javaSlotToBedrock(SmithingInventoryTranslator.MATERIAL)); + slotPacket.setItem(ItemData.AIR); + session.sendUpstreamPacket(slotPacket); + + session.getInventoryTranslator().updateSlot(session, inventory, SmithingInventoryTranslator.MATERIAL); + }, 150, TimeUnit.MILLISECONDS)); + } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaOpenScreenTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaOpenScreenTranslator.java index edb13f806..bc4e22b5a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaOpenScreenTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaOpenScreenTranslator.java @@ -52,8 +52,9 @@ public class JavaOpenScreenTranslator extends PacketTranslator { + + @Override + public void translate(GeyserSession session, ClientboundSetCursorItemPacket packet) { + GeyserItemStack newItem = GeyserItemStack.from(packet.getContents()); + session.getPlayerInventory().setCursor(newItem, session); + InventoryUtils.updateCursor(session); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaSetPlayerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaSetPlayerInventoryTranslator.java new file mode 100644 index 000000000..58b30bfc8 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaSetPlayerInventoryTranslator.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.translator.protocol.java.inventory; + +import org.geysermc.geyser.GeyserLogger; +import org.geysermc.geyser.inventory.GeyserItemStack; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.inventory.InventoryTranslator; +import org.geysermc.geyser.translator.protocol.PacketTranslator; +import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundSetPlayerInventoryPacket; + +@Translator(packet = ClientboundSetPlayerInventoryPacket.class) +public class JavaSetPlayerInventoryTranslator extends PacketTranslator { + + @Override + public void translate(GeyserSession session, ClientboundSetPlayerInventoryPacket packet) { + int slot = packet.getSlot(); + if (slot >= 0 && slot <= 8) { + // As of 1.21.3 - can be replicated in vanilla server survival by picking an item in-world in your inventory not in your hotbar. + slot = session.getPlayerInventory().getOffsetForHotbar(slot); + } + + if (slot >= session.getPlayerInventory().getSize()) { + GeyserLogger logger = session.getGeyser().getLogger(); + logger.warning("ClientboundSetPlayerInventoryPacket sent to " + session.bedrockUsername() + + " that exceeds inventory size!"); + if (logger.isDebug()) { + logger.debug(packet.toString()); + logger.debug(session.getPlayerInventory().toString()); + } + return; + } + + session.getPlayerInventory().setItem(slot, GeyserItemStack.from(packet.getContents()), session); + InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR.updateSlot(session, session.getPlayerInventory(), slot); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaCooldownTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaCooldownTranslator.java index 636671651..2b14f015f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaCooldownTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaCooldownTranslator.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.translator.protocol.java.level; +import net.kyori.adventure.key.Key; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundCooldownPacket; import org.cloudburstmc.protocol.bedrock.packet.PlayerStartItemCooldownPacket; import org.geysermc.geyser.item.Items; @@ -39,7 +40,11 @@ public class JavaCooldownTranslator extends PacketTranslator { //TODO DustParticleData data = (DustParticleData) particle.getData(); - int r = (int) (data.getRed() * 255); - int g = (int) (data.getGreen() * 255); - int b = (int) (data.getBlue() * 255); - int rgbData = ((0xff) << 24) | ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff); + int rgbData = data.getColor(); return (position) -> { LevelEventPacket packet = new LevelEventPacket(); packet.setType(ParticleType.FALLING_DUST); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSetTimeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSetTimeTranslator.java index 43ef0870a..b7a92dbd4 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSetTimeTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSetTimeTranslator.java @@ -36,11 +36,9 @@ public class JavaSetTimeTranslator extends PacketTranslator= 0) { - // Client thinks there is no daylight cycle but there is - session.setDaylightCycle(true); - } else if (session.isDaylightCycle() && time < 0) { - // Client thinks there is daylight cycle but there isn't - session.setDaylightCycle(false); + + // We need to send a gamerule if this changed + if (session.isDaylightCycle() != packet.isTickDayTime()) { + session.setDaylightCycle(packet.isTickDayTime()); } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/sound/block/ComparatorSoundInteractionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/sound/block/ComparatorSoundInteractionTranslator.java index 9d5d3cd59..745b51117 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/sound/block/ComparatorSoundInteractionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/sound/block/ComparatorSoundInteractionTranslator.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.translator.sound.block; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.LevelEvent; import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; +import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.sound.BlockSoundInteractionTranslator; @@ -38,12 +39,10 @@ public class ComparatorSoundInteractionTranslator implements BlockSoundInteracti @Override public void translate(GeyserSession session, Vector3f position, BlockState state) { - String identifier = state.toString(); - boolean powered = identifier.contains("mode=compare"); LevelEventPacket levelEventPacket = new LevelEventPacket(); levelEventPacket.setPosition(position); levelEventPacket.setType(LevelEvent.SOUND_CLICK); //TODO: New ID? - levelEventPacket.setData(powered ? 500 : 550); + levelEventPacket.setData(state.getValue(Properties.MODE_COMPARATOR).equals("compare") ? 500 : 550); session.sendUpstreamPacket(levelEventPacket); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/sound/block/GrassPathInteractionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/sound/block/GrassPathInteractionTranslator.java index a25beaa50..d601d5561 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/sound/block/GrassPathInteractionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/sound/block/GrassPathInteractionTranslator.java @@ -29,7 +29,6 @@ import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket; import org.geysermc.geyser.level.block.type.BlockState; -import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.sound.BlockSoundInteractionTranslator; import org.geysermc.geyser.translator.sound.SoundTranslator; @@ -39,14 +38,13 @@ public class GrassPathInteractionTranslator implements BlockSoundInteractionTran @Override public void translate(GeyserSession session, Vector3f position, BlockState state) { - String identifier = state.toString(); LevelSoundEventPacket levelSoundEventPacket = new LevelSoundEventPacket(); levelSoundEventPacket.setPosition(position); levelSoundEventPacket.setBabySound(false); levelSoundEventPacket.setRelativeVolumeDisabled(false); levelSoundEventPacket.setIdentifier(":"); levelSoundEventPacket.setSound(SoundEvent.ITEM_USE_ON); - levelSoundEventPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getInt(identifier))); + levelSoundEventPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(state.javaId())); session.sendUpstreamPacket(levelSoundEventPacket); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/sound/block/HoeInteractionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/sound/block/HoeInteractionTranslator.java index 1a583ab8a..f30aa7493 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/sound/block/HoeInteractionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/sound/block/HoeInteractionTranslator.java @@ -29,7 +29,6 @@ import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket; import org.geysermc.geyser.level.block.type.BlockState; -import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.sound.BlockSoundInteractionTranslator; import org.geysermc.geyser.translator.sound.SoundTranslator; @@ -39,14 +38,13 @@ public class HoeInteractionTranslator implements BlockSoundInteractionTranslator @Override public void translate(GeyserSession session, Vector3f position, BlockState state) { - String identifier = state.toString(); LevelSoundEventPacket levelSoundEventPacket = new LevelSoundEventPacket(); levelSoundEventPacket.setPosition(position); levelSoundEventPacket.setBabySound(false); levelSoundEventPacket.setRelativeVolumeDisabled(false); levelSoundEventPacket.setIdentifier(":"); levelSoundEventPacket.setSound(SoundEvent.ITEM_USE_ON); - levelSoundEventPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getInt(identifier))); + levelSoundEventPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(state.javaId())); session.sendUpstreamPacket(levelSoundEventPacket); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/sound/block/LeverSoundInteractionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/sound/block/LeverSoundInteractionTranslator.java index fd045739c..2f596f6aa 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/sound/block/LeverSoundInteractionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/sound/block/LeverSoundInteractionTranslator.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.translator.sound.block; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.LevelEvent; import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; +import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.sound.BlockSoundInteractionTranslator; @@ -38,12 +39,10 @@ public class LeverSoundInteractionTranslator implements BlockSoundInteractionTra @Override public void translate(GeyserSession session, Vector3f position, BlockState state) { - String identifier = state.toString(); - boolean powered = identifier.contains("powered=true"); LevelEventPacket levelEventPacket = new LevelEventPacket(); levelEventPacket.setPosition(position); levelEventPacket.setType(LevelEvent.SOUND_CLICK); - levelEventPacket.setData(powered ? 600 : 500); + levelEventPacket.setData(state.getValue(Properties.POWERED) ? 600 : 500); session.sendUpstreamPacket(levelEventPacket); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/sound/block/OpenableSoundInteractionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/sound/block/OpenableSoundInteractionTranslator.java index 93d55ca33..05a4804af 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/sound/block/OpenableSoundInteractionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/sound/block/OpenableSoundInteractionTranslator.java @@ -26,10 +26,9 @@ package org.geysermc.geyser.translator.sound.block; import org.cloudburstmc.math.vector.Vector3f; -import org.cloudburstmc.protocol.bedrock.data.LevelEvent; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; -import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket; +import org.geysermc.geyser.level.block.property.Properties; import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.sound.BlockSoundInteractionTranslator; @@ -42,7 +41,7 @@ public class OpenableSoundInteractionTranslator implements BlockSoundInteraction public void translate(GeyserSession session, Vector3f position, BlockState state) { String identifier = state.toString(); if (identifier.contains("iron")) return; - SoundEvent event = getSound(identifier.contains("open=true"), identifier); + SoundEvent event = getSound(state.getValue(Properties.OPEN, false), identifier); LevelSoundEventPacket levelSoundEventPacket = new LevelSoundEventPacket(); levelSoundEventPacket.setPosition(position.add(0.5, 0.5, 0.5)); levelSoundEventPacket.setBabySound(false); diff --git a/core/src/main/java/org/geysermc/geyser/translator/text/MessageTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/text/MessageTranslator.java index eca86ff32..5c3b21b5a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/text/MessageTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/text/MessageTranslator.java @@ -137,6 +137,18 @@ public class MessageTranslator { return convertMessage(message, locale, true); } + /** + * Convert a Java message to the legacy format ready for bedrock, for use in item tooltips + * (a gray color is applied). + * + * @param message Java message + * @param locale Locale to use for translation strings + * @return Parsed and formatted message for bedrock, in gray color + */ + public static String convertMessageForTooltip(Component message, String locale) { + return RESET + ChatColor.GRAY + convertMessageRaw(message, locale); + } + /** * Convert a Java message to the legacy format ready for bedrock. Unlike {@link #convertMessage(Component, String)} * this version does not add a leading color reset. In Bedrock some places have build-in colors. @@ -422,6 +434,15 @@ public class MessageTranslator { return convertMessage(session, parsed); } + /** + * Deserialize an NbtMap with a description text component (usually provided from a registry) into a Bedrock-formatted string. + */ + public static String deserializeDescriptionForTooltip(GeyserSession session, NbtMap tag) { + Object description = tag.get("description"); + Component parsed = componentFromNbtTag(description); + return convertMessageForTooltip(parsed, session.locale()); + } + public static Component componentFromNbtTag(Object nbtTag) { return componentFromNbtTag(nbtTag, Style.empty()); } diff --git a/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java b/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java index e73fe1a34..6367b2d14 100644 --- a/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java @@ -223,10 +223,6 @@ public final class BlockUtils { return getCollision(session.getGeyser().getWorldManager().getBlockAt(session, blockPos)); } - public static BlockCollision getCollisionAt(GeyserSession session, int x, int y, int z) { - return getCollision(session.getGeyser().getWorldManager().getBlockAt(session, x, y, z)); - } - private BlockUtils() { } } diff --git a/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java b/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java index f8b20fbc4..034975b15 100644 --- a/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.util; -import java.util.Locale; import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -35,6 +34,7 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.BoatEntity; +import org.geysermc.geyser.entity.type.ChestBoatEntity; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.TextDisplayEntity; import org.geysermc.geyser.entity.type.living.ArmorStandEntity; @@ -49,6 +49,8 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; +import java.util.Locale; + public final class EntityUtils { /** * A constant array of the two hands that a player can interact with an entity. @@ -93,6 +95,10 @@ public final class EntityUtils { } private static float getMountedHeightOffset(Entity mount) { + if (mount instanceof BoatEntity boat && boat.getVariant() != BoatEntity.BoatVariant.BAMBOO) { + return -0.1f; + } + float height = mount.getBoundingBoxHeight(); float mountedHeightOffset = height * 0.75f; switch (mount.getDefinition().entityType()) { @@ -105,10 +111,7 @@ public final class EntityUtils { case TRADER_LLAMA, LLAMA -> mountedHeightOffset = height * 0.6f; case MINECART, HOPPER_MINECART, TNT_MINECART, CHEST_MINECART, FURNACE_MINECART, SPAWNER_MINECART, COMMAND_BLOCK_MINECART -> mountedHeightOffset = 0; - case BOAT, CHEST_BOAT -> { - boolean isBamboo = ((BoatEntity) mount).getVariant() == 8; - mountedHeightOffset = isBamboo ? 0.25f : -0.1f; - } + case BAMBOO_RAFT, BAMBOO_CHEST_RAFT -> mountedHeightOffset = 0.25f; case HOGLIN, ZOGLIN -> { boolean isBaby = mount.getFlag(EntityFlag.BABY); mountedHeightOffset = height - (isBaby ? 0.2f : 0.15f); @@ -174,15 +177,6 @@ public final class EntityUtils { float yOffset = mountedHeightOffset + heightOffset; float zOffset = 0; switch (mount.getDefinition().entityType()) { - case BOAT -> { - // Without the X offset, more than one entity on a boat is stacked on top of each other - if (moreThanOneEntity) { - xOffset = rider ? 0.2f : -0.6f; - if (passenger instanceof AnimalEntity) { - xOffset += 0.2f; - } - } - } case CAMEL -> { zOffset = 0.5f; if (moreThanOneEntity) { @@ -201,7 +195,6 @@ public final class EntityUtils { } } } - case CHEST_BOAT -> xOffset = 0.15F; case CHICKEN -> zOffset = -0.1f; case TRADER_LLAMA, LLAMA -> zOffset = -0.3f; case TEXT_DISPLAY -> { @@ -217,6 +210,17 @@ public final class EntityUtils { } } } + if (mount instanceof ChestBoatEntity) { + xOffset = 0.15F; + } else if (mount instanceof BoatEntity) { + // Without the X offset, more than one entity on a boat is stacked on top of each other + if (moreThanOneEntity) { + xOffset = rider ? 0.2f : -0.6f; + if (passenger instanceof AnimalEntity) { + xOffset += 0.2f; + } + } + } /* * Bedrock Differences * Zoglin & Hoglin seem to be taller in Bedrock edition @@ -231,13 +235,19 @@ public final class EntityUtils { } switch (mount.getDefinition().entityType()) { case MINECART, HOPPER_MINECART, TNT_MINECART, CHEST_MINECART, FURNACE_MINECART, SPAWNER_MINECART, - COMMAND_BLOCK_MINECART, BOAT, CHEST_BOAT -> yOffset -= mount.getDefinition().height() * 0.5f; + COMMAND_BLOCK_MINECART -> yOffset -= mount.getDefinition().height() * 0.5f; } switch (passenger.getDefinition().entityType()) { case MINECART, HOPPER_MINECART, TNT_MINECART, CHEST_MINECART, FURNACE_MINECART, SPAWNER_MINECART, - COMMAND_BLOCK_MINECART, BOAT, CHEST_BOAT -> yOffset += passenger.getDefinition().height() * 0.5f; + COMMAND_BLOCK_MINECART -> yOffset += passenger.getDefinition().height() * 0.5f; case FALLING_BLOCK -> yOffset += 0.5f; } + if (mount instanceof BoatEntity) { + yOffset -= mount.getDefinition().height() * 0.5f; + } + if (passenger instanceof BoatEntity) { + yOffset += passenger.getDefinition().height() * 0.5f; + } if (mount instanceof ArmorStandEntity armorStand) { yOffset -= armorStand.getYOffset(); } diff --git a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java index dd7be0136..9862eb730 100644 --- a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java @@ -49,9 +49,10 @@ import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.level.BedrockDimension; import org.geysermc.geyser.registry.Registries; -import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.registry.JavaRegistries; +import org.geysermc.geyser.session.cache.tags.Tag; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.translator.inventory.InventoryTranslator; @@ -60,15 +61,22 @@ import org.geysermc.geyser.translator.inventory.chest.DoubleChestInventoryTransl import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; -import org.geysermc.mcprotocollib.protocol.data.game.recipe.Ingredient; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.CompositeSlotDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.EmptySlotDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.ItemSlotDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.ItemStackSlotDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.SlotDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.TagSlotDisplay; +import org.geysermc.mcprotocollib.protocol.data.game.recipe.display.slot.WithRemainderSlotDisplay; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClosePacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundPickItemPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundSetCreativeModeSlotPacket; import org.jetbrains.annotations.Contract; -import java.util.Arrays; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Objects; import java.util.concurrent.TimeUnit; import java.util.function.IntFunction; @@ -305,14 +313,7 @@ public class InventoryUtils { // If we still have not found the item, and we're in creative, ask for the item from the server. if (session.getGameMode() == GameMode.CREATIVE) { - int slot = findEmptyHotbarSlot(inventory); - - ServerboundSetCreativeModeSlotPacket actionPacket = new ServerboundSetCreativeModeSlotPacket((short) slot, - itemStack); - if ((slot - 36) != inventory.getHeldItemSlot()) { - setHotbarItem(session, slot); - } - session.sendDownstreamGamePacket(actionPacket); + setPickedItem(session, inventory, GeyserItemStack.from(itemStack)); } } @@ -372,24 +373,15 @@ public class InventoryUtils { return; } - // If we still have not found the item, and we're in creative, ask for the item from the server. + // If we still have not found the item, and we're in creative, set the item ourselves. if (session.getGameMode() == GameMode.CREATIVE) { - int slot = findEmptyHotbarSlot(inventory); - - ItemMapping mapping = session.getItemMappings().getMapping(item); - ServerboundSetCreativeModeSlotPacket actionPacket = new ServerboundSetCreativeModeSlotPacket((short)slot, - new ItemStack(mapping.getJavaItem().javaId())); - if ((slot - 36) != inventory.getHeldItemSlot()) { - setHotbarItem(session, slot); - } - session.sendDownstreamGamePacket(actionPacket); + GeyserItemStack itemStack = item.newItemStack(1, null); + setPickedItem(session, inventory, itemStack); } } - /** - * @return the first empty slot found in this inventory, or else the player's currently held slot. - */ - private static int findEmptyHotbarSlot(PlayerInventory inventory) { + private static void setPickedItem(GeyserSession session, PlayerInventory inventory, GeyserItemStack itemStack) { + // Try to find an empty hotbar slot. int slot = inventory.getHeldItemSlot() + 36; if (!inventory.getItemInHand().isEmpty()) { // Otherwise we should just use the current slot for (int i = 36; i < 45; i++) { @@ -399,7 +391,32 @@ public class InventoryUtils { } } } - return slot; + GeyserItemStack existingItem = inventory.getItem(slot); + if (!existingItem.isEmpty()) { + // Try to move the item to another slot. + for (int i = 9; i < 36; i++) { + if (inventory.getItem(i).isEmpty()) { + inventory.setItem(i, existingItem, session); + InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR.updateSlot(session, inventory, i); + + ServerboundSetCreativeModeSlotPacket actionPacket = new ServerboundSetCreativeModeSlotPacket((short) i, + existingItem.getItemStack()); + session.sendDownstreamGamePacket(actionPacket); + break; + } + } + } + + // As of 1.21.3 - the client does this on its own end and the server doesn't send a slot response back. + inventory.setItem(slot, itemStack, session); + InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR.updateSlot(session, inventory, slot); + + ServerboundSetCreativeModeSlotPacket actionPacket = new ServerboundSetCreativeModeSlotPacket((short) slot, + itemStack.getItemStack()); + if ((slot - 36) != inventory.getHeldItemSlot()) { + setHotbarItem(session, slot); + } + session.sendDownstreamGamePacket(actionPacket); } /** @@ -433,6 +450,38 @@ public class InventoryUtils { }; } + /** + * Returns if the provided item stack would be accepted by the slot display. + */ + public static boolean acceptsAsInput(GeyserSession session, SlotDisplay slotDisplay, GeyserItemStack itemStack) { + if (slotDisplay instanceof EmptySlotDisplay) { + return itemStack.isEmpty(); + } + if (slotDisplay instanceof CompositeSlotDisplay compositeSlotDisplay) { + if (compositeSlotDisplay.contents().size() == 1) { + return acceptsAsInput(session, compositeSlotDisplay.contents().get(0), itemStack); + } + return compositeSlotDisplay.contents().stream().anyMatch(aSlotDisplay -> acceptsAsInput(session, aSlotDisplay, itemStack)); + } + if (slotDisplay instanceof WithRemainderSlotDisplay remainderSlotDisplay) { + return acceptsAsInput(session, remainderSlotDisplay.input(), itemStack); + } + if (slotDisplay instanceof ItemSlotDisplay itemSlotDisplay) { + return itemStack.getJavaId() == itemSlotDisplay.item(); + } + if (slotDisplay instanceof ItemStackSlotDisplay itemStackSlotDisplay) { + ItemStack other = itemStackSlotDisplay.itemStack(); + // Amount check might be flimsy? + return itemStack.getJavaId() == other.getId() && itemStack.getAmount() >= other.getAmount() + && Objects.equals(itemStack.getComponents(), other.getDataComponents()); + } + if (slotDisplay instanceof TagSlotDisplay tagSlotDisplay) { + return session.getTagCache().is(new Tag<>(JavaRegistries.ITEM, tagSlotDisplay.tag()), itemStack.asItem()); + } + session.getGeyser().getLogger().warning("Unknown slot display type: " + slotDisplay); + return false; + } + /** * Test all known recipes to find a valid match * @@ -454,59 +503,55 @@ public class InventoryUtils { for (GeyserRecipe recipe : session.getCraftingRecipes().values()) { if (recipe.isShaped()) { GeyserShapedRecipe shapedRecipe = (GeyserShapedRecipe) recipe; - if (output != null && !shapedRecipe.result().equals(output)) { + if (output != null && !acceptsAsInput(session, shapedRecipe.result(), GeyserItemStack.from(output))) { continue; } - Ingredient[] ingredients = shapedRecipe.ingredients(); - if (shapedRecipe.width() != width || shapedRecipe.height() != height || width * height != ingredients.length) { + List ingredients = shapedRecipe.ingredients(); + if (shapedRecipe.width() != width || shapedRecipe.height() != height || width * height != ingredients.size()) { continue; } - if (!testShapedRecipe(ingredients, inventoryGetter, gridDimensions, firstRow, height, firstCol, width)) { - Ingredient[] mirroredIngredients = new Ingredient[ingredients.length]; + if (!testShapedRecipe(session, ingredients, inventoryGetter, gridDimensions, firstRow, height, firstCol, width)) { + List mirroredIngredients = new ArrayList<>(ingredients.size()); for (int row = 0; row < height; row++) { for (int col = 0; col < width; col++) { - mirroredIngredients[col + (row * width)] = ingredients[(width - 1 - col) + (row * width)]; + int index = col + (row * width); + while (mirroredIngredients.size() <= index) { + mirroredIngredients.add(null); + } + mirroredIngredients.set(index, ingredients.get((width - 1 - col) + (row * width))); } } - if (Arrays.equals(ingredients, mirroredIngredients) || - !testShapedRecipe(mirroredIngredients, inventoryGetter, gridDimensions, firstRow, height, firstCol, width)) { + if (ingredients.equals(mirroredIngredients) || + !testShapedRecipe(session, mirroredIngredients, inventoryGetter, gridDimensions, firstRow, height, firstCol, width)) { continue; } } } else { GeyserShapelessRecipe data = (GeyserShapelessRecipe) recipe; - if (output != null && !data.result().equals(output)) { + if (output != null && !acceptsAsInput(session, data.result(), GeyserItemStack.from(output))) { continue; } - if (nonAirCount != data.ingredients().length) { + if (nonAirCount != data.ingredients().size()) { // There is an amount of items on the crafting table that is not the same as the ingredient count so this is invalid continue; } - for (int i = 0; i < data.ingredients().length; i++) { - Ingredient ingredient = data.ingredients()[i]; - for (ItemStack itemStack : ingredient.getOptions()) { - boolean inventoryHasItem = false; - // Iterate only over the crafting table to find this item - crafting: - for (int row = firstRow; row < height + firstRow; row++) { - for (int col = firstCol; col < width + firstCol; col++) { - GeyserItemStack geyserItemStack = inventoryGetter.apply(col + (row * gridDimensions) + 1); - if (geyserItemStack.isEmpty()) { - inventoryHasItem = itemStack == null || itemStack.getId() == 0; - if (inventoryHasItem) { - break crafting; - } - } else if (itemStack.equals(geyserItemStack.getItemStack(1))) { - inventoryHasItem = true; - break crafting; - } + for (int i = 0; i < data.ingredients().size(); i++) { + SlotDisplay slotDisplay = data.ingredients().get(i); + boolean inventoryHasItem = false; + // Iterate only over the crafting table to find this item + for (int row = firstRow; row < height + firstRow; row++) { + for (int col = firstCol; col < width + firstCol; col++) { + GeyserItemStack geyserItemStack = inventoryGetter.apply(col + (row * gridDimensions) + 1); + if (acceptsAsInput(session, slotDisplay, geyserItemStack)) { + inventoryHasItem = true; + break; } } - if (!inventoryHasItem) { - continue recipes; - } + } + if (!inventoryHasItem) { + continue recipes; } } } @@ -516,28 +561,15 @@ public class InventoryUtils { } @SuppressWarnings("BooleanMethodIsAlwaysInverted") - private static boolean testShapedRecipe(final Ingredient[] ingredients, final IntFunction inventoryGetter, + private static boolean testShapedRecipe(final GeyserSession session, final List ingredients, final IntFunction inventoryGetter, final int gridDimensions, final int firstRow, final int height, final int firstCol, final int width) { int ingredientIndex = 0; for (int row = firstRow; row < height + firstRow; row++) { for (int col = firstCol; col < width + firstCol; col++) { GeyserItemStack geyserItemStack = inventoryGetter.apply(col + (row * gridDimensions) + 1); - Ingredient ingredient = ingredients[ingredientIndex++]; - if (ingredient.getOptions().length == 0) { - if (!geyserItemStack.isEmpty()) { - return false; - } - } else { - boolean inventoryHasItem = false; - for (ItemStack item : ingredient.getOptions()) { - if (Objects.equals(geyserItemStack.getItemStack(1), item)) { - inventoryHasItem = true; - break; - } - } - if (!inventoryHasItem) { - return false; - } + SlotDisplay slotDisplay = ingredients.get(ingredientIndex++); + if (!acceptsAsInput(session, slotDisplay, geyserItemStack)) { + return false; } } } diff --git a/core/src/main/java/org/geysermc/geyser/util/SoundUtils.java b/core/src/main/java/org/geysermc/geyser/util/SoundUtils.java index 693ce136a..d1c1c77e3 100644 --- a/core/src/main/java/org/geysermc/geyser/util/SoundUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/SoundUtils.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.util; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; +import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.protocol.bedrock.data.LevelEvent; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; @@ -162,6 +163,20 @@ public final class SoundUtils { session.sendUpstreamPacket(soundPacket); } + public static String readSoundEvent(NbtMap data, String context) { + Object soundEventObject = data.get("sound_event"); + String soundEvent; + if (soundEventObject instanceof NbtMap map) { + soundEvent = map.getString("sound_id"); + } else if (soundEventObject instanceof String string) { + soundEvent = string; + } else { + soundEvent = ""; + GeyserImpl.getInstance().getLogger().debug("Sound event for " + context + " was of an unexpected type! Expected string or NBT map, got " + soundEventObject); + } + return soundEvent; + } + private SoundUtils() { } } diff --git a/core/src/main/resources/bedrock/item_tags.1_20_80.json b/core/src/main/resources/bedrock/item_tags.1_20_80.json new file mode 100644 index 000000000..4203c96c1 --- /dev/null +++ b/core/src/main/resources/bedrock/item_tags.1_20_80.json @@ -0,0 +1,784 @@ +{ + "minecraft:arrow": [ + "minecraft:arrow" + ], + "minecraft:banner": [ + "minecraft:banner" + ], + "minecraft:boat": [ + "minecraft:oak_boat", + "minecraft:birch_boat", + "minecraft:jungle_boat", + "minecraft:spruce_boat", + "minecraft:mangrove_boat", + "minecraft:acacia_boat", + "minecraft:oak_chest_boat", + "minecraft:dark_oak_boat", + "minecraft:birch_chest_boat", + "minecraft:jungle_chest_boat", + "minecraft:spruce_chest_boat", + "minecraft:acacia_chest_boat", + "minecraft:dark_oak_chest_boat", + "minecraft:mangrove_chest_boat", + "minecraft:cherry_boat", + "minecraft:cherry_chest_boat", + "minecraft:bamboo_raft", + "minecraft:bamboo_chest_raft" + ], + "minecraft:boats": [ + "minecraft:oak_boat", + "minecraft:birch_boat", + "minecraft:jungle_boat", + "minecraft:spruce_boat", + "minecraft:mangrove_boat", + "minecraft:acacia_boat", + "minecraft:oak_chest_boat", + "minecraft:dark_oak_boat", + "minecraft:birch_chest_boat", + "minecraft:jungle_chest_boat", + "minecraft:spruce_chest_boat", + "minecraft:acacia_chest_boat", + "minecraft:dark_oak_chest_boat", + "minecraft:mangrove_chest_boat", + "minecraft:cherry_boat", + "minecraft:cherry_chest_boat", + "minecraft:bamboo_raft", + "minecraft:bamboo_chest_raft" + ], + "minecraft:bookshelf_books": [ + "minecraft:book", + "minecraft:writable_book", + "minecraft:enchanted_book", + "minecraft:written_book" + ], + "minecraft:chainmail_tier": [ + "minecraft:chainmail_helmet", + "minecraft:chainmail_leggings", + "minecraft:chainmail_chestplate", + "minecraft:chainmail_boots" + ], + "minecraft:chest_boat": [], + "minecraft:coals": [ + "minecraft:coal", + "minecraft:charcoal" + ], + "minecraft:crimson_stems": [ + "minecraft:crimson_hyphae", + "minecraft:stripped_crimson_hyphae", + "minecraft:crimson_stem", + "minecraft:stripped_crimson_stem" + ], + "minecraft:decorated_pot_sherds": [ + "minecraft:blade_pottery_sherd", + "minecraft:brick", + "minecraft:angler_pottery_sherd", + "minecraft:burn_pottery_sherd", + "minecraft:archer_pottery_sherd", + "minecraft:arms_up_pottery_sherd", + "minecraft:heartbreak_pottery_sherd", + "minecraft:brewer_pottery_sherd", + "minecraft:danger_pottery_sherd", + "minecraft:explorer_pottery_sherd", + "minecraft:friend_pottery_sherd", + "minecraft:heart_pottery_sherd", + "minecraft:howl_pottery_sherd", + "minecraft:miner_pottery_sherd", + "minecraft:mourner_pottery_sherd", + "minecraft:plenty_pottery_sherd", + "minecraft:skull_pottery_sherd", + "minecraft:prize_pottery_sherd", + "minecraft:sheaf_pottery_sherd", + "minecraft:shelter_pottery_sherd", + "minecraft:snort_pottery_sherd" + ], + "minecraft:diamond_tier": [ + "minecraft:diamond_axe", + "minecraft:diamond_sword", + "minecraft:diamond_pickaxe", + "minecraft:diamond_shovel", + "minecraft:diamond_hoe", + "minecraft:diamond_helmet", + "minecraft:diamond_chestplate", + "minecraft:diamond_leggings", + "minecraft:diamond_boots" + ], + "minecraft:digger": [ + "minecraft:stone_pickaxe", + "minecraft:iron_pickaxe", + "minecraft:iron_shovel", + "minecraft:iron_axe", + "minecraft:wooden_shovel", + "minecraft:wooden_pickaxe", + "minecraft:stone_shovel", + "minecraft:wooden_axe", + "minecraft:stone_axe", + "minecraft:diamond_shovel", + "minecraft:diamond_pickaxe", + "minecraft:diamond_axe", + "minecraft:golden_shovel", + "minecraft:golden_pickaxe", + "minecraft:golden_axe", + "minecraft:wooden_hoe", + "minecraft:stone_hoe", + "minecraft:iron_hoe", + "minecraft:diamond_hoe", + "minecraft:golden_hoe", + "minecraft:netherite_shovel", + "minecraft:netherite_pickaxe", + "minecraft:netherite_axe", + "minecraft:netherite_hoe" + ], + "minecraft:door": [ + "minecraft:wooden_door", + "minecraft:iron_door", + "minecraft:spruce_door", + "minecraft:birch_door", + "minecraft:crimson_door", + "minecraft:jungle_door", + "minecraft:dark_oak_door", + "minecraft:acacia_door", + "minecraft:mangrove_door", + "minecraft:warped_door", + "minecraft:cherry_door", + "minecraft:bamboo_door" + ], + "minecraft:golden_tier": [ + "minecraft:golden_sword", + "minecraft:golden_hoe", + "minecraft:golden_shovel", + "minecraft:golden_chestplate", + "minecraft:golden_pickaxe", + "minecraft:golden_axe", + "minecraft:golden_leggings", + "minecraft:golden_helmet", + "minecraft:golden_boots" + ], + "minecraft:hanging_actor": [ + "minecraft:painting" + ], + "minecraft:hanging_sign": [ + "minecraft:cherry_hanging_sign", + "minecraft:oak_hanging_sign", + "minecraft:crimson_hanging_sign", + "minecraft:acacia_hanging_sign", + "minecraft:spruce_hanging_sign", + "minecraft:birch_hanging_sign", + "minecraft:jungle_hanging_sign", + "minecraft:dark_oak_hanging_sign", + "minecraft:warped_hanging_sign", + "minecraft:mangrove_hanging_sign", + "minecraft:bamboo_hanging_sign" + ], + "minecraft:horse_armor": [ + "minecraft:leather_horse_armor", + "minecraft:iron_horse_armor", + "minecraft:golden_horse_armor", + "minecraft:diamond_horse_armor" + ], + "minecraft:iron_tier": [ + "minecraft:iron_pickaxe", + "minecraft:iron_shovel", + "minecraft:iron_sword", + "minecraft:iron_axe", + "minecraft:iron_hoe", + "minecraft:iron_chestplate", + "minecraft:iron_helmet", + "minecraft:iron_leggings", + "minecraft:iron_boots" + ], + "minecraft:is_armor": [ + "minecraft:leather_boots", + "minecraft:leather_leggings", + "minecraft:leather_helmet", + "minecraft:leather_chestplate", + "minecraft:chainmail_leggings", + "minecraft:elytra", + "minecraft:chainmail_helmet", + "minecraft:chainmail_chestplate", + "minecraft:chainmail_boots", + "minecraft:iron_helmet", + "minecraft:iron_chestplate", + "minecraft:iron_leggings", + "minecraft:iron_boots", + "minecraft:diamond_helmet", + "minecraft:diamond_chestplate", + "minecraft:diamond_leggings", + "minecraft:diamond_boots", + "minecraft:golden_helmet", + "minecraft:golden_chestplate", + "minecraft:golden_leggings", + "minecraft:golden_boots", + "minecraft:turtle_helmet", + "minecraft:netherite_helmet", + "minecraft:netherite_chestplate", + "minecraft:netherite_leggings", + "minecraft:netherite_boots" + ], + "minecraft:is_axe": [ + "minecraft:iron_axe", + "minecraft:wooden_axe", + "minecraft:diamond_axe", + "minecraft:netherite_axe", + "minecraft:stone_axe", + "minecraft:golden_axe" + ], + "minecraft:is_cooked": [ + "minecraft:cooked_porkchop", + "minecraft:cooked_cod", + "minecraft:rabbit_stew", + "minecraft:cooked_salmon", + "minecraft:cooked_beef", + "minecraft:cooked_chicken", + "minecraft:cooked_rabbit", + "minecraft:cooked_mutton" + ], + "minecraft:is_fish": [ + "minecraft:cod", + "minecraft:salmon", + "minecraft:tropical_fish", + "minecraft:pufferfish", + "minecraft:cooked_salmon", + "minecraft:cooked_cod" + ], + "minecraft:is_food": [ + "minecraft:porkchop", + "minecraft:cooked_mutton", + "minecraft:apple", + "minecraft:golden_apple", + "minecraft:dried_kelp", + "minecraft:cooked_porkchop", + "minecraft:mushroom_stew", + "minecraft:enchanted_golden_apple", + "minecraft:bread", + "minecraft:cookie", + "minecraft:melon_slice", + "minecraft:beef", + "minecraft:cooked_beef", + "minecraft:chicken", + "minecraft:cooked_chicken", + "minecraft:rotten_flesh", + "minecraft:carrot", + "minecraft:potato", + "minecraft:baked_potato", + "minecraft:golden_carrot", + "minecraft:pumpkin_pie", + "minecraft:beetroot", + "minecraft:beetroot_soup", + "minecraft:sweet_berries", + "minecraft:rabbit", + "minecraft:cooked_rabbit", + "minecraft:rabbit_stew", + "minecraft:mutton" + ], + "minecraft:is_hoe": [ + "minecraft:wooden_hoe", + "minecraft:stone_hoe", + "minecraft:iron_hoe", + "minecraft:netherite_hoe", + "minecraft:diamond_hoe", + "minecraft:golden_hoe" + ], + "minecraft:is_meat": [ + "minecraft:rotten_flesh", + "minecraft:porkchop", + "minecraft:cooked_mutton", + "minecraft:cooked_porkchop", + "minecraft:cooked_chicken", + "minecraft:beef", + "minecraft:rabbit", + "minecraft:cooked_beef", + "minecraft:chicken", + "minecraft:cooked_rabbit", + "minecraft:rabbit_stew", + "minecraft:mutton" + ], + "minecraft:is_minecart": [ + "minecraft:minecart", + "minecraft:tnt_minecart", + "minecraft:chest_minecart", + "minecraft:hopper_minecart", + "minecraft:command_block_minecart" + ], + "minecraft:is_pickaxe": [ + "minecraft:iron_pickaxe", + "minecraft:stone_pickaxe", + "minecraft:netherite_pickaxe", + "minecraft:wooden_pickaxe", + "minecraft:diamond_pickaxe", + "minecraft:golden_pickaxe" + ], + "minecraft:is_shovel": [ + "minecraft:iron_shovel", + "minecraft:golden_shovel", + "minecraft:wooden_shovel", + "minecraft:stone_shovel", + "minecraft:diamond_shovel", + "minecraft:netherite_shovel" + ], + "minecraft:is_sword": [ + "minecraft:iron_sword", + "minecraft:wooden_sword", + "minecraft:stone_sword", + "minecraft:golden_sword", + "minecraft:diamond_sword", + "minecraft:netherite_sword" + ], + "minecraft:is_tool": [ + "minecraft:iron_pickaxe", + "minecraft:iron_shovel", + "minecraft:iron_sword", + "minecraft:stone_hoe", + "minecraft:iron_axe", + "minecraft:wooden_sword", + "minecraft:diamond_hoe", + "minecraft:wooden_shovel", + "minecraft:golden_sword", + "minecraft:wooden_pickaxe", + "minecraft:wooden_axe", + "minecraft:stone_sword", + "minecraft:stone_shovel", + "minecraft:stone_pickaxe", + "minecraft:stone_axe", + "minecraft:diamond_sword", + "minecraft:diamond_axe", + "minecraft:diamond_shovel", + "minecraft:diamond_pickaxe", + "minecraft:golden_shovel", + "minecraft:golden_pickaxe", + "minecraft:golden_axe", + "minecraft:wooden_hoe", + "minecraft:netherite_sword", + "minecraft:iron_hoe", + "minecraft:golden_hoe", + "minecraft:netherite_shovel", + "minecraft:netherite_pickaxe", + "minecraft:netherite_axe", + "minecraft:netherite_hoe" + ], + "minecraft:is_trident": [ + "minecraft:trident" + ], + "minecraft:leather_tier": [ + "minecraft:leather_helmet", + "minecraft:leather_leggings", + "minecraft:leather_boots", + "minecraft:leather_chestplate" + ], + "minecraft:lectern_books": [ + "minecraft:writable_book", + "minecraft:written_book" + ], + "minecraft:logs": [ + "minecraft:oak_log", + "minecraft:stripped_oak_wood", + "minecraft:spruce_log", + "minecraft:crimson_stem", + "minecraft:birch_log", + "minecraft:jungle_log", + "minecraft:dark_oak_wood", + "minecraft:oak_wood", + "minecraft:dark_oak_log", + "minecraft:acacia_log", + "minecraft:spruce_wood", + "minecraft:stripped_spruce_wood", + "minecraft:birch_wood", + "minecraft:stripped_birch_wood", + "minecraft:warped_hyphae", + "minecraft:jungle_wood", + "minecraft:stripped_jungle_wood", + "minecraft:stripped_warped_stem", + "minecraft:acacia_wood", + "minecraft:stripped_acacia_wood", + "minecraft:stripped_dark_oak_wood", + "minecraft:mangrove_log", + "minecraft:stripped_spruce_log", + "minecraft:stripped_dark_oak_log", + "minecraft:stripped_jungle_log", + "minecraft:stripped_crimson_stem", + "minecraft:mangrove_wood", + "minecraft:stripped_mangrove_wood", + "minecraft:crimson_hyphae", + "minecraft:stripped_cherry_log", + "minecraft:stripped_cherry_wood", + "minecraft:stripped_acacia_log", + "minecraft:stripped_warped_hyphae", + "minecraft:stripped_birch_log", + "minecraft:warped_stem", + "minecraft:stripped_crimson_hyphae", + "minecraft:cherry_wood", + "minecraft:stripped_oak_log", + "minecraft:cherry_log", + "minecraft:stripped_mangrove_log" + ], + "minecraft:logs_that_burn": [ + "minecraft:oak_log", + "minecraft:stripped_oak_wood", + "minecraft:spruce_log", + "minecraft:birch_log", + "minecraft:jungle_log", + "minecraft:dark_oak_wood", + "minecraft:oak_wood", + "minecraft:dark_oak_log", + "minecraft:acacia_log", + "minecraft:spruce_wood", + "minecraft:stripped_spruce_wood", + "minecraft:birch_wood", + "minecraft:stripped_birch_wood", + "minecraft:jungle_wood", + "minecraft:stripped_jungle_wood", + "minecraft:acacia_wood", + "minecraft:stripped_acacia_wood", + "minecraft:stripped_dark_oak_wood", + "minecraft:mangrove_log", + "minecraft:stripped_spruce_log", + "minecraft:stripped_dark_oak_log", + "minecraft:stripped_jungle_log", + "minecraft:mangrove_wood", + "minecraft:stripped_mangrove_wood", + "minecraft:stripped_cherry_log", + "minecraft:stripped_cherry_wood", + "minecraft:stripped_acacia_log", + "minecraft:stripped_birch_log", + "minecraft:cherry_wood", + "minecraft:stripped_oak_log", + "minecraft:cherry_log", + "minecraft:stripped_mangrove_log" + ], + "minecraft:mangrove_logs": [ + "minecraft:mangrove_log", + "minecraft:mangrove_wood", + "minecraft:stripped_mangrove_wood", + "minecraft:stripped_mangrove_log" + ], + "minecraft:music_disc": [ + "minecraft:music_disc_stal", + "minecraft:music_disc_13", + "minecraft:music_disc_cat", + "minecraft:music_disc_11", + "minecraft:music_disc_blocks", + "minecraft:music_disc_mellohi", + "minecraft:music_disc_chirp", + "minecraft:music_disc_ward", + "minecraft:music_disc_far", + "minecraft:music_disc_mall", + "minecraft:music_disc_strad", + "minecraft:music_disc_wait", + "minecraft:music_disc_otherside", + "minecraft:music_disc_pigstep", + "minecraft:music_disc_5", + "minecraft:music_disc_relic" + ], + "minecraft:netherite_tier": [ + "minecraft:netherite_chestplate", + "minecraft:netherite_axe", + "minecraft:netherite_sword", + "minecraft:netherite_hoe", + "minecraft:netherite_shovel", + "minecraft:netherite_pickaxe", + "minecraft:netherite_helmet", + "minecraft:netherite_leggings", + "minecraft:netherite_boots" + ], + "minecraft:piglin_loved": [], + "minecraft:piglin_repellents": [], + "minecraft:planks": [ + "minecraft:dark_oak_planks", + "minecraft:oak_planks", + "minecraft:warped_planks", + "minecraft:spruce_planks", + "minecraft:birch_planks", + "minecraft:jungle_planks", + "minecraft:mangrove_planks", + "minecraft:acacia_planks", + "minecraft:crimson_planks", + "minecraft:bamboo_planks", + "minecraft:cherry_planks" + ], + "minecraft:sand": [ + "minecraft:sand" + ], + "minecraft:sign": [ + "minecraft:dark_oak_sign", + "minecraft:oak_sign", + "minecraft:spruce_sign", + "minecraft:crimson_sign", + "minecraft:birch_sign", + "minecraft:jungle_sign", + "minecraft:warped_sign", + "minecraft:bamboo_sign", + "minecraft:acacia_sign", + "minecraft:mangrove_sign", + "minecraft:crimson_hanging_sign", + "minecraft:cherry_sign", + "minecraft:acacia_hanging_sign", + "minecraft:cherry_hanging_sign", + "minecraft:oak_hanging_sign", + "minecraft:spruce_hanging_sign", + "minecraft:birch_hanging_sign", + "minecraft:jungle_hanging_sign", + "minecraft:dark_oak_hanging_sign", + "minecraft:warped_hanging_sign", + "minecraft:mangrove_hanging_sign", + "minecraft:bamboo_hanging_sign" + ], + "minecraft:soul_fire_base_blocks": [ + "minecraft:soul_soil", + "minecraft:soul_sand" + ], + "minecraft:spawn_egg": [ + "minecraft:zombie_villager_spawn_egg", + "minecraft:ender_dragon_spawn_egg", + "minecraft:zombie_horse_spawn_egg", + "minecraft:creeper_spawn_egg", + "minecraft:chicken_spawn_egg", + "minecraft:skeleton_spawn_egg", + "minecraft:cow_spawn_egg", + "minecraft:pig_spawn_egg", + "minecraft:dolphin_spawn_egg", + "minecraft:sheep_spawn_egg", + "minecraft:slime_spawn_egg", + "minecraft:wolf_spawn_egg", + "minecraft:phantom_spawn_egg", + "minecraft:mooshroom_spawn_egg", + "minecraft:agent_spawn_egg", + "minecraft:enderman_spawn_egg", + "minecraft:silverfish_spawn_egg", + "minecraft:zoglin_spawn_egg", + "minecraft:fox_spawn_egg", + "minecraft:spider_spawn_egg", + "minecraft:zombie_spawn_egg", + "minecraft:bat_spawn_egg", + "minecraft:zombie_pigman_spawn_egg", + "minecraft:villager_spawn_egg", + "minecraft:vex_spawn_egg", + "minecraft:llama_spawn_egg", + "minecraft:squid_spawn_egg", + "minecraft:cat_spawn_egg", + "minecraft:ocelot_spawn_egg", + "minecraft:witch_spawn_egg", + "minecraft:ghast_spawn_egg", + "minecraft:allay_spawn_egg", + "minecraft:strider_spawn_egg", + "minecraft:magma_cube_spawn_egg", + "minecraft:blaze_spawn_egg", + "minecraft:cave_spider_spawn_egg", + "minecraft:guardian_spawn_egg", + "minecraft:horse_spawn_egg", + "minecraft:husk_spawn_egg", + "minecraft:rabbit_spawn_egg", + "minecraft:endermite_spawn_egg", + "minecraft:mule_spawn_egg", + "minecraft:stray_spawn_egg", + "minecraft:wither_skeleton_spawn_egg", + "minecraft:donkey_spawn_egg", + "minecraft:skeleton_horse_spawn_egg", + "minecraft:shulker_spawn_egg", + "minecraft:npc_spawn_egg", + "minecraft:elder_guardian_spawn_egg", + "minecraft:polar_bear_spawn_egg", + "minecraft:cod_spawn_egg", + "minecraft:vindicator_spawn_egg", + "minecraft:evoker_spawn_egg", + "minecraft:parrot_spawn_egg", + "minecraft:tropical_fish_spawn_egg", + "minecraft:pufferfish_spawn_egg", + "minecraft:salmon_spawn_egg", + "minecraft:drowned_spawn_egg", + "minecraft:turtle_spawn_egg", + "minecraft:piglin_spawn_egg", + "minecraft:panda_spawn_egg", + "minecraft:pillager_spawn_egg", + "minecraft:wandering_trader_spawn_egg", + "minecraft:ravager_spawn_egg", + "minecraft:bee_spawn_egg", + "minecraft:hoglin_spawn_egg", + "minecraft:piglin_brute_spawn_egg", + "minecraft:sniffer_spawn_egg", + "minecraft:axolotl_spawn_egg", + "minecraft:goat_spawn_egg", + "minecraft:glow_squid_spawn_egg", + "minecraft:iron_golem_spawn_egg", + "minecraft:snow_golem_spawn_egg", + "minecraft:wither_spawn_egg", + "minecraft:frog_spawn_egg", + "minecraft:tadpole_spawn_egg", + "minecraft:warden_spawn_egg", + "minecraft:trader_llama_spawn_egg", + "minecraft:camel_spawn_egg", + "minecraft:armadillo_spawn_egg", + "minecraft:spawn_egg" + ], + "minecraft:stone_bricks": [ + "minecraft:stonebrick" + ], + "minecraft:stone_crafting_materials": [ + "minecraft:cobblestone", + "minecraft:cobbled_deepslate", + "minecraft:blackstone" + ], + "minecraft:stone_tier": [ + "minecraft:stone_sword", + "minecraft:stone_shovel", + "minecraft:stone_pickaxe", + "minecraft:stone_axe", + "minecraft:stone_hoe" + ], + "minecraft:stone_tool_materials": [ + "minecraft:cobblestone", + "minecraft:cobbled_deepslate", + "minecraft:blackstone" + ], + "minecraft:transform_materials": [ + "minecraft:netherite_ingot" + ], + "minecraft:transform_templates": [ + "minecraft:netherite_upgrade_smithing_template" + ], + "minecraft:transformable_items": [ + "minecraft:diamond_axe", + "minecraft:diamond_sword", + "minecraft:diamond_pickaxe", + "minecraft:diamond_shovel", + "minecraft:diamond_hoe", + "minecraft:diamond_helmet", + "minecraft:diamond_chestplate", + "minecraft:diamond_leggings", + "minecraft:diamond_boots", + "minecraft:golden_boots" + ], + "minecraft:trim_materials": [ + "minecraft:diamond", + "minecraft:emerald", + "minecraft:iron_ingot", + "minecraft:quartz", + "minecraft:lapis_lazuli", + "minecraft:gold_ingot", + "minecraft:redstone", + "minecraft:copper_ingot", + "minecraft:netherite_ingot", + "minecraft:amethyst_shard" + ], + "minecraft:trim_templates": [ + "minecraft:tide_armor_trim_smithing_template", + "minecraft:sentry_armor_trim_smithing_template", + "minecraft:coast_armor_trim_smithing_template", + "minecraft:dune_armor_trim_smithing_template", + "minecraft:wild_armor_trim_smithing_template", + "minecraft:ward_armor_trim_smithing_template", + "minecraft:eye_armor_trim_smithing_template", + "minecraft:vex_armor_trim_smithing_template", + "minecraft:snout_armor_trim_smithing_template", + "minecraft:rib_armor_trim_smithing_template", + "minecraft:spire_armor_trim_smithing_template", + "minecraft:silence_armor_trim_smithing_template", + "minecraft:wayfinder_armor_trim_smithing_template", + "minecraft:raiser_armor_trim_smithing_template", + "minecraft:shaper_armor_trim_smithing_template", + "minecraft:host_armor_trim_smithing_template" + ], + "minecraft:trimmable_armors": [ + "minecraft:leather_boots", + "minecraft:leather_leggings", + "minecraft:leather_helmet", + "minecraft:leather_chestplate", + "minecraft:chainmail_leggings", + "minecraft:chainmail_helmet", + "minecraft:chainmail_chestplate", + "minecraft:chainmail_boots", + "minecraft:iron_helmet", + "minecraft:iron_chestplate", + "minecraft:iron_leggings", + "minecraft:iron_boots", + "minecraft:diamond_helmet", + "minecraft:diamond_chestplate", + "minecraft:diamond_leggings", + "minecraft:diamond_boots", + "minecraft:golden_helmet", + "minecraft:golden_chestplate", + "minecraft:golden_leggings", + "minecraft:golden_boots", + "minecraft:turtle_helmet", + "minecraft:netherite_helmet", + "minecraft:netherite_chestplate", + "minecraft:netherite_leggings", + "minecraft:netherite_boots" + ], + "minecraft:vibration_damper": [ + "minecraft:pink_wool", + "minecraft:lime_wool", + "minecraft:white_wool", + "minecraft:magenta_wool", + "minecraft:red_wool", + "minecraft:orange_wool", + "minecraft:yellow_carpet", + "minecraft:light_blue_wool", + "minecraft:yellow_wool", + "minecraft:gray_wool", + "minecraft:light_gray_wool", + "minecraft:cyan_wool", + "minecraft:purple_wool", + "minecraft:purple_carpet", + "minecraft:blue_wool", + "minecraft:brown_wool", + "minecraft:green_wool", + "minecraft:black_wool", + "minecraft:white_carpet", + "minecraft:orange_carpet", + "minecraft:magenta_carpet", + "minecraft:light_blue_carpet", + "minecraft:lime_carpet", + "minecraft:pink_carpet", + "minecraft:gray_carpet", + "minecraft:light_gray_carpet", + "minecraft:cyan_carpet", + "minecraft:blue_carpet", + "minecraft:brown_carpet", + "minecraft:green_carpet", + "minecraft:red_carpet", + "minecraft:black_carpet" + ], + "minecraft:warped_stems": [ + "minecraft:stripped_warped_hyphae", + "minecraft:warped_hyphae", + "minecraft:stripped_warped_stem", + "minecraft:warped_stem" + ], + "minecraft:wooden_slabs": [ + "minecraft:mangrove_slab", + "minecraft:birch_slab", + "minecraft:cherry_slab", + "minecraft:jungle_slab", + "minecraft:spruce_slab", + "minecraft:bamboo_slab", + "minecraft:oak_slab", + "minecraft:acacia_slab", + "minecraft:dark_oak_slab", + "minecraft:crimson_slab", + "minecraft:warped_slab" + ], + "minecraft:wooden_tier": [ + "minecraft:wooden_sword", + "minecraft:wooden_shovel", + "minecraft:wooden_pickaxe", + "minecraft:wooden_axe", + "minecraft:wooden_hoe" + ], + "minecraft:wool": [ + "minecraft:pink_wool", + "minecraft:lime_wool", + "minecraft:white_wool", + "minecraft:magenta_wool", + "minecraft:red_wool", + "minecraft:orange_wool", + "minecraft:light_blue_wool", + "minecraft:yellow_wool", + "minecraft:gray_wool", + "minecraft:light_gray_wool", + "minecraft:cyan_wool", + "minecraft:purple_wool", + "minecraft:blue_wool", + "minecraft:brown_wool", + "minecraft:green_wool", + "minecraft:black_wool" + ] +} \ No newline at end of file diff --git a/core/src/main/resources/bedrock/item_tags.1_21_0.json b/core/src/main/resources/bedrock/item_tags.1_21_0.json new file mode 100644 index 000000000..5fac99114 --- /dev/null +++ b/core/src/main/resources/bedrock/item_tags.1_21_0.json @@ -0,0 +1,802 @@ +{ + "minecraft:arrow": [ + "minecraft:arrow" + ], + "minecraft:banner": [ + "minecraft:banner" + ], + "minecraft:boat": [ + "minecraft:cherry_chest_boat", + "minecraft:oak_chest_boat", + "minecraft:mangrove_boat", + "minecraft:oak_boat", + "minecraft:birch_boat", + "minecraft:jungle_boat", + "minecraft:spruce_boat", + "minecraft:acacia_boat", + "minecraft:dark_oak_boat", + "minecraft:birch_chest_boat", + "minecraft:jungle_chest_boat", + "minecraft:spruce_chest_boat", + "minecraft:acacia_chest_boat", + "minecraft:dark_oak_chest_boat", + "minecraft:mangrove_chest_boat", + "minecraft:cherry_boat", + "minecraft:bamboo_raft", + "minecraft:bamboo_chest_raft" + ], + "minecraft:boats": [ + "minecraft:cherry_chest_boat", + "minecraft:oak_chest_boat", + "minecraft:mangrove_boat", + "minecraft:oak_boat", + "minecraft:birch_boat", + "minecraft:jungle_boat", + "minecraft:spruce_boat", + "minecraft:acacia_boat", + "minecraft:dark_oak_boat", + "minecraft:birch_chest_boat", + "minecraft:jungle_chest_boat", + "minecraft:spruce_chest_boat", + "minecraft:acacia_chest_boat", + "minecraft:dark_oak_chest_boat", + "minecraft:mangrove_chest_boat", + "minecraft:cherry_boat", + "minecraft:bamboo_raft", + "minecraft:bamboo_chest_raft" + ], + "minecraft:bookshelf_books": [ + "minecraft:written_book", + "minecraft:book", + "minecraft:writable_book", + "minecraft:enchanted_book" + ], + "minecraft:chainmail_tier": [ + "minecraft:chainmail_helmet", + "minecraft:chainmail_chestplate", + "minecraft:chainmail_leggings", + "minecraft:chainmail_boots" + ], + "minecraft:coals": [ + "minecraft:coal", + "minecraft:charcoal" + ], + "minecraft:crimson_stems": [ + "minecraft:stripped_crimson_stem", + "minecraft:crimson_hyphae", + "minecraft:crimson_stem", + "minecraft:stripped_crimson_hyphae" + ], + "minecraft:decorated_pot_sherds": [ + "minecraft:skull_pottery_sherd", + "minecraft:angler_pottery_sherd", + "minecraft:prize_pottery_sherd", + "minecraft:mourner_pottery_sherd", + "minecraft:arms_up_pottery_sherd", + "minecraft:burn_pottery_sherd", + "minecraft:snort_pottery_sherd", + "minecraft:brick", + "minecraft:heartbreak_pottery_sherd", + "minecraft:miner_pottery_sherd", + "minecraft:brewer_pottery_sherd", + "minecraft:plenty_pottery_sherd", + "minecraft:scrape_pottery_sherd", + "minecraft:howl_pottery_sherd", + "minecraft:explorer_pottery_sherd", + "minecraft:archer_pottery_sherd", + "minecraft:blade_pottery_sherd", + "minecraft:danger_pottery_sherd", + "minecraft:flow_pottery_sherd", + "minecraft:friend_pottery_sherd", + "minecraft:guster_pottery_sherd", + "minecraft:heart_pottery_sherd", + "minecraft:sheaf_pottery_sherd", + "minecraft:shelter_pottery_sherd" + ], + "minecraft:diamond_tier": [ + "minecraft:diamond_sword", + "minecraft:diamond_shovel", + "minecraft:diamond_pickaxe", + "minecraft:diamond_axe", + "minecraft:mace", + "minecraft:diamond_hoe", + "minecraft:diamond_helmet", + "minecraft:diamond_chestplate", + "minecraft:diamond_leggings", + "minecraft:diamond_boots" + ], + "minecraft:digger": [ + "minecraft:iron_pickaxe", + "minecraft:wooden_pickaxe", + "minecraft:wooden_shovel", + "minecraft:iron_axe", + "minecraft:iron_shovel", + "minecraft:stone_shovel", + "minecraft:wooden_axe", + "minecraft:stone_pickaxe", + "minecraft:stone_axe", + "minecraft:diamond_shovel", + "minecraft:diamond_pickaxe", + "minecraft:diamond_axe", + "minecraft:golden_shovel", + "minecraft:golden_pickaxe", + "minecraft:golden_axe", + "minecraft:wooden_hoe", + "minecraft:stone_hoe", + "minecraft:iron_hoe", + "minecraft:diamond_hoe", + "minecraft:golden_hoe", + "minecraft:netherite_pickaxe", + "minecraft:netherite_shovel", + "minecraft:netherite_axe", + "minecraft:netherite_hoe" + ], + "minecraft:door": [ + "minecraft:warped_door", + "minecraft:waxed_weathered_copper_door", + "minecraft:wooden_door", + "minecraft:iron_door", + "minecraft:mangrove_door", + "minecraft:exposed_copper_door", + "minecraft:bamboo_door", + "minecraft:weathered_copper_door", + "minecraft:jungle_door", + "minecraft:spruce_door", + "minecraft:birch_door", + "minecraft:acacia_door", + "minecraft:dark_oak_door", + "minecraft:crimson_door", + "minecraft:cherry_door", + "minecraft:copper_door", + "minecraft:oxidized_copper_door", + "minecraft:waxed_copper_door", + "minecraft:waxed_exposed_copper_door", + "minecraft:waxed_oxidized_copper_door" + ], + "minecraft:golden_tier": [ + "minecraft:golden_sword", + "minecraft:golden_shovel", + "minecraft:golden_pickaxe", + "minecraft:golden_axe", + "minecraft:golden_hoe", + "minecraft:golden_helmet", + "minecraft:golden_chestplate", + "minecraft:golden_leggings", + "minecraft:golden_boots" + ], + "minecraft:hanging_actor": [ + "minecraft:painting" + ], + "minecraft:hanging_sign": [ + "minecraft:mangrove_hanging_sign", + "minecraft:bamboo_hanging_sign", + "minecraft:spruce_hanging_sign", + "minecraft:birch_hanging_sign", + "minecraft:cherry_hanging_sign", + "minecraft:oak_hanging_sign", + "minecraft:jungle_hanging_sign", + "minecraft:acacia_hanging_sign", + "minecraft:dark_oak_hanging_sign", + "minecraft:crimson_hanging_sign", + "minecraft:warped_hanging_sign" + ], + "minecraft:horse_armor": [ + "minecraft:golden_horse_armor", + "minecraft:leather_horse_armor", + "minecraft:iron_horse_armor", + "minecraft:diamond_horse_armor" + ], + "minecraft:iron_tier": [ + "minecraft:iron_sword", + "minecraft:iron_pickaxe", + "minecraft:iron_axe", + "minecraft:iron_shovel", + "minecraft:iron_hoe", + "minecraft:iron_helmet", + "minecraft:iron_chestplate", + "minecraft:iron_leggings", + "minecraft:iron_boots" + ], + "minecraft:is_armor": [ + "minecraft:netherite_boots", + "minecraft:chainmail_helmet", + "minecraft:elytra", + "minecraft:leather_helmet", + "minecraft:leather_chestplate", + "minecraft:leather_leggings", + "minecraft:leather_boots", + "minecraft:chainmail_chestplate", + "minecraft:chainmail_leggings", + "minecraft:chainmail_boots", + "minecraft:iron_helmet", + "minecraft:iron_chestplate", + "minecraft:iron_leggings", + "minecraft:iron_boots", + "minecraft:diamond_helmet", + "minecraft:diamond_chestplate", + "minecraft:diamond_leggings", + "minecraft:diamond_boots", + "minecraft:golden_helmet", + "minecraft:golden_chestplate", + "minecraft:golden_leggings", + "minecraft:golden_boots", + "minecraft:turtle_helmet", + "minecraft:netherite_chestplate", + "minecraft:netherite_leggings", + "minecraft:netherite_helmet" + ], + "minecraft:is_axe": [ + "minecraft:iron_axe", + "minecraft:wooden_axe", + "minecraft:stone_axe", + "minecraft:diamond_axe", + "minecraft:golden_axe", + "minecraft:netherite_axe" + ], + "minecraft:is_cooked": [ + "minecraft:cooked_cod", + "minecraft:cooked_porkchop", + "minecraft:cooked_rabbit", + "minecraft:cooked_salmon", + "minecraft:cooked_beef", + "minecraft:cooked_chicken", + "minecraft:rabbit_stew", + "minecraft:cooked_mutton" + ], + "minecraft:is_fish": [ + "minecraft:cooked_cod", + "minecraft:cod", + "minecraft:salmon", + "minecraft:tropical_fish", + "minecraft:pufferfish", + "minecraft:cooked_salmon" + ], + "minecraft:is_food": [ + "minecraft:rabbit", + "minecraft:cooked_porkchop", + "minecraft:mushroom_stew", + "minecraft:beetroot", + "minecraft:apple", + "minecraft:carrot", + "minecraft:chicken", + "minecraft:potato", + "minecraft:enchanted_golden_apple", + "minecraft:sweet_berries", + "minecraft:golden_apple", + "minecraft:bread", + "minecraft:porkchop", + "minecraft:cookie", + "minecraft:cooked_rabbit", + "minecraft:beef", + "minecraft:dried_kelp", + "minecraft:beetroot_soup", + "minecraft:melon_slice", + "minecraft:cooked_beef", + "minecraft:rotten_flesh", + "minecraft:cooked_chicken", + "minecraft:baked_potato", + "minecraft:golden_carrot", + "minecraft:pumpkin_pie", + "minecraft:rabbit_stew", + "minecraft:cooked_mutton", + "minecraft:mutton" + ], + "minecraft:is_hoe": [ + "minecraft:wooden_hoe", + "minecraft:stone_hoe", + "minecraft:iron_hoe", + "minecraft:diamond_hoe", + "minecraft:golden_hoe", + "minecraft:netherite_hoe" + ], + "minecraft:is_meat": [ + "minecraft:rabbit", + "minecraft:cooked_porkchop", + "minecraft:chicken", + "minecraft:porkchop", + "minecraft:cooked_rabbit", + "minecraft:beef", + "minecraft:cooked_beef", + "minecraft:rotten_flesh", + "minecraft:cooked_chicken", + "minecraft:rabbit_stew", + "minecraft:cooked_mutton", + "minecraft:mutton" + ], + "minecraft:is_minecart": [ + "minecraft:command_block_minecart", + "minecraft:minecart", + "minecraft:chest_minecart", + "minecraft:tnt_minecart", + "minecraft:hopper_minecart" + ], + "minecraft:is_pickaxe": [ + "minecraft:iron_pickaxe", + "minecraft:wooden_pickaxe", + "minecraft:stone_pickaxe", + "minecraft:diamond_pickaxe", + "minecraft:golden_pickaxe", + "minecraft:netherite_pickaxe" + ], + "minecraft:is_shovel": [ + "minecraft:wooden_shovel", + "minecraft:iron_shovel", + "minecraft:stone_shovel", + "minecraft:diamond_shovel", + "minecraft:golden_shovel", + "minecraft:netherite_shovel" + ], + "minecraft:is_sword": [ + "minecraft:iron_sword", + "minecraft:stone_sword", + "minecraft:wooden_sword", + "minecraft:diamond_sword", + "minecraft:mace", + "minecraft:golden_sword", + "minecraft:netherite_sword" + ], + "minecraft:is_tool": [ + "minecraft:iron_sword", + "minecraft:iron_pickaxe", + "minecraft:wooden_pickaxe", + "minecraft:wooden_shovel", + "minecraft:stone_sword", + "minecraft:iron_axe", + "minecraft:iron_shovel", + "minecraft:stone_shovel", + "minecraft:wooden_sword", + "minecraft:wooden_axe", + "minecraft:stone_pickaxe", + "minecraft:stone_axe", + "minecraft:diamond_sword", + "minecraft:diamond_shovel", + "minecraft:diamond_pickaxe", + "minecraft:diamond_axe", + "minecraft:mace", + "minecraft:golden_sword", + "minecraft:golden_shovel", + "minecraft:golden_pickaxe", + "minecraft:golden_axe", + "minecraft:wooden_hoe", + "minecraft:stone_hoe", + "minecraft:iron_hoe", + "minecraft:diamond_hoe", + "minecraft:golden_hoe", + "minecraft:netherite_sword", + "minecraft:netherite_pickaxe", + "minecraft:netherite_shovel", + "minecraft:netherite_axe", + "minecraft:netherite_hoe" + ], + "minecraft:is_trident": [ + "minecraft:trident" + ], + "minecraft:leather_tier": [ + "minecraft:leather_helmet", + "minecraft:leather_chestplate", + "minecraft:leather_leggings", + "minecraft:leather_boots" + ], + "minecraft:lectern_books": [ + "minecraft:written_book", + "minecraft:writable_book" + ], + "minecraft:logs": [ + "minecraft:stripped_oak_log", + "minecraft:mangrove_wood", + "minecraft:spruce_wood", + "minecraft:stripped_cherry_wood", + "minecraft:stripped_crimson_stem", + "minecraft:stripped_spruce_wood", + "minecraft:spruce_log", + "minecraft:acacia_wood", + "minecraft:stripped_acacia_wood", + "minecraft:stripped_warped_hyphae", + "minecraft:acacia_log", + "minecraft:oak_log", + "minecraft:birch_log", + "minecraft:jungle_log", + "minecraft:dark_oak_log", + "minecraft:jungle_wood", + "minecraft:stripped_jungle_wood", + "minecraft:oak_wood", + "minecraft:stripped_oak_wood", + "minecraft:birch_wood", + "minecraft:stripped_birch_wood", + "minecraft:dark_oak_wood", + "minecraft:stripped_dark_oak_wood", + "minecraft:stripped_dark_oak_log", + "minecraft:mangrove_log", + "minecraft:stripped_jungle_log", + "minecraft:stripped_mangrove_wood", + "minecraft:crimson_hyphae", + "minecraft:stripped_cherry_log", + "minecraft:stripped_birch_log", + "minecraft:stripped_acacia_log", + "minecraft:crimson_stem", + "minecraft:warped_hyphae", + "minecraft:stripped_spruce_log", + "minecraft:warped_stem", + "minecraft:stripped_crimson_hyphae", + "minecraft:cherry_wood", + "minecraft:cherry_log", + "minecraft:stripped_warped_stem", + "minecraft:stripped_mangrove_log" + ], + "minecraft:logs_that_burn": [ + "minecraft:stripped_oak_log", + "minecraft:mangrove_wood", + "minecraft:spruce_wood", + "minecraft:stripped_cherry_wood", + "minecraft:stripped_spruce_wood", + "minecraft:spruce_log", + "minecraft:acacia_wood", + "minecraft:stripped_acacia_wood", + "minecraft:acacia_log", + "minecraft:oak_log", + "minecraft:birch_log", + "minecraft:jungle_log", + "minecraft:dark_oak_log", + "minecraft:jungle_wood", + "minecraft:stripped_jungle_wood", + "minecraft:oak_wood", + "minecraft:stripped_oak_wood", + "minecraft:birch_wood", + "minecraft:stripped_birch_wood", + "minecraft:dark_oak_wood", + "minecraft:stripped_dark_oak_wood", + "minecraft:stripped_dark_oak_log", + "minecraft:mangrove_log", + "minecraft:stripped_jungle_log", + "minecraft:stripped_mangrove_wood", + "minecraft:stripped_cherry_log", + "minecraft:stripped_birch_log", + "minecraft:stripped_acacia_log", + "minecraft:stripped_spruce_log", + "minecraft:cherry_wood", + "minecraft:cherry_log", + "minecraft:stripped_mangrove_log" + ], + "minecraft:mangrove_logs": [ + "minecraft:mangrove_wood", + "minecraft:mangrove_log", + "minecraft:stripped_mangrove_wood", + "minecraft:stripped_mangrove_log" + ], + "minecraft:music_disc": [ + "minecraft:music_disc_ward", + "minecraft:music_disc_strad", + "minecraft:music_disc_chirp", + "minecraft:music_disc_creator_music_box", + "minecraft:music_disc_mall", + "minecraft:music_disc_pigstep", + "minecraft:music_disc_wait", + "minecraft:music_disc_11", + "minecraft:music_disc_stal", + "minecraft:music_disc_13", + "minecraft:music_disc_cat", + "minecraft:music_disc_blocks", + "minecraft:music_disc_far", + "minecraft:music_disc_mellohi", + "minecraft:music_disc_otherside", + "minecraft:music_disc_5", + "minecraft:music_disc_relic", + "minecraft:music_disc_creator", + "minecraft:music_disc_precipice" + ], + "minecraft:netherite_tier": [ + "minecraft:netherite_boots", + "minecraft:netherite_sword", + "minecraft:netherite_chestplate", + "minecraft:netherite_pickaxe", + "minecraft:netherite_leggings", + "minecraft:netherite_shovel", + "minecraft:netherite_axe", + "minecraft:netherite_hoe", + "minecraft:netherite_helmet" + ], + "minecraft:planks": [ + "minecraft:spruce_planks", + "minecraft:oak_planks", + "minecraft:mangrove_planks", + "minecraft:birch_planks", + "minecraft:jungle_planks", + "minecraft:acacia_planks", + "minecraft:dark_oak_planks", + "minecraft:bamboo_planks", + "minecraft:warped_planks", + "minecraft:crimson_planks", + "minecraft:cherry_planks" + ], + "minecraft:sand": [ + "minecraft:sand" + ], + "minecraft:sign": [ + "minecraft:bamboo_sign", + "minecraft:mangrove_hanging_sign", + "minecraft:cherry_sign", + "minecraft:oak_sign", + "minecraft:bamboo_hanging_sign", + "minecraft:warped_sign", + "minecraft:spruce_sign", + "minecraft:spruce_hanging_sign", + "minecraft:acacia_sign", + "minecraft:birch_hanging_sign", + "minecraft:birch_sign", + "minecraft:jungle_sign", + "minecraft:dark_oak_sign", + "minecraft:mangrove_sign", + "minecraft:crimson_sign", + "minecraft:cherry_hanging_sign", + "minecraft:oak_hanging_sign", + "minecraft:jungle_hanging_sign", + "minecraft:acacia_hanging_sign", + "minecraft:dark_oak_hanging_sign", + "minecraft:crimson_hanging_sign", + "minecraft:warped_hanging_sign" + ], + "minecraft:soul_fire_base_blocks": [ + "minecraft:soul_sand", + "minecraft:soul_soil" + ], + "minecraft:spawn_egg": [ + "minecraft:enderman_spawn_egg", + "minecraft:ravager_spawn_egg", + "minecraft:strider_spawn_egg", + "minecraft:slime_spawn_egg", + "minecraft:glow_squid_spawn_egg", + "minecraft:pillager_spawn_egg", + "minecraft:blaze_spawn_egg", + "minecraft:witch_spawn_egg", + "minecraft:horse_spawn_egg", + "minecraft:polar_bear_spawn_egg", + "minecraft:zoglin_spawn_egg", + "minecraft:stray_spawn_egg", + "minecraft:zombie_pigman_spawn_egg", + "minecraft:snow_golem_spawn_egg", + "minecraft:panda_spawn_egg", + "minecraft:axolotl_spawn_egg", + "minecraft:agent_spawn_egg", + "minecraft:shulker_spawn_egg", + "minecraft:vindicator_spawn_egg", + "minecraft:evoker_spawn_egg", + "minecraft:parrot_spawn_egg", + "minecraft:wolf_spawn_egg", + "minecraft:elder_guardian_spawn_egg", + "minecraft:silverfish_spawn_egg", + "minecraft:tadpole_spawn_egg", + "minecraft:cow_spawn_egg", + "minecraft:bogged_spawn_egg", + "minecraft:ocelot_spawn_egg", + "minecraft:bee_spawn_egg", + "minecraft:piglin_brute_spawn_egg", + "minecraft:rabbit_spawn_egg", + "minecraft:camel_spawn_egg", + "minecraft:creeper_spawn_egg", + "minecraft:drowned_spawn_egg", + "minecraft:chicken_spawn_egg", + "minecraft:pig_spawn_egg", + "minecraft:sheep_spawn_egg", + "minecraft:mooshroom_spawn_egg", + "minecraft:skeleton_spawn_egg", + "minecraft:spider_spawn_egg", + "minecraft:zombie_spawn_egg", + "minecraft:villager_spawn_egg", + "minecraft:squid_spawn_egg", + "minecraft:bat_spawn_egg", + "minecraft:ghast_spawn_egg", + "minecraft:magma_cube_spawn_egg", + "minecraft:cave_spider_spawn_egg", + "minecraft:endermite_spawn_egg", + "minecraft:guardian_spawn_egg", + "minecraft:husk_spawn_egg", + "minecraft:piglin_spawn_egg", + "minecraft:wither_skeleton_spawn_egg", + "minecraft:donkey_spawn_egg", + "minecraft:mule_spawn_egg", + "minecraft:skeleton_horse_spawn_egg", + "minecraft:zombie_horse_spawn_egg", + "minecraft:npc_spawn_egg", + "minecraft:breeze_spawn_egg", + "minecraft:llama_spawn_egg", + "minecraft:vex_spawn_egg", + "minecraft:warden_spawn_egg", + "minecraft:zombie_villager_spawn_egg", + "minecraft:tropical_fish_spawn_egg", + "minecraft:cod_spawn_egg", + "minecraft:pufferfish_spawn_egg", + "minecraft:salmon_spawn_egg", + "minecraft:dolphin_spawn_egg", + "minecraft:turtle_spawn_egg", + "minecraft:phantom_spawn_egg", + "minecraft:cat_spawn_egg", + "minecraft:fox_spawn_egg", + "minecraft:wandering_trader_spawn_egg", + "minecraft:hoglin_spawn_egg", + "minecraft:sniffer_spawn_egg", + "minecraft:goat_spawn_egg", + "minecraft:iron_golem_spawn_egg", + "minecraft:ender_dragon_spawn_egg", + "minecraft:wither_spawn_egg", + "minecraft:frog_spawn_egg", + "minecraft:allay_spawn_egg", + "minecraft:trader_llama_spawn_egg", + "minecraft:armadillo_spawn_egg", + "minecraft:spawn_egg" + ], + "minecraft:stone_bricks": [ + "minecraft:stonebrick" + ], + "minecraft:stone_crafting_materials": [ + "minecraft:cobblestone", + "minecraft:cobbled_deepslate", + "minecraft:blackstone" + ], + "minecraft:stone_tier": [ + "minecraft:stone_sword", + "minecraft:stone_shovel", + "minecraft:stone_pickaxe", + "minecraft:stone_axe", + "minecraft:stone_hoe" + ], + "minecraft:stone_tool_materials": [ + "minecraft:cobblestone", + "minecraft:cobbled_deepslate", + "minecraft:blackstone" + ], + "minecraft:transform_materials": [ + "minecraft:netherite_ingot" + ], + "minecraft:transform_templates": [ + "minecraft:netherite_upgrade_smithing_template" + ], + "minecraft:transformable_items": [ + "minecraft:diamond_sword", + "minecraft:diamond_shovel", + "minecraft:diamond_pickaxe", + "minecraft:diamond_axe", + "minecraft:diamond_hoe", + "minecraft:diamond_helmet", + "minecraft:diamond_chestplate", + "minecraft:diamond_leggings", + "minecraft:diamond_boots", + "minecraft:golden_boots" + ], + "minecraft:trim_materials": [ + "minecraft:gold_ingot", + "minecraft:iron_ingot", + "minecraft:diamond", + "minecraft:redstone", + "minecraft:netherite_ingot", + "minecraft:lapis_lazuli", + "minecraft:quartz", + "minecraft:copper_ingot", + "minecraft:emerald", + "minecraft:amethyst_shard" + ], + "minecraft:trim_templates": [ + "minecraft:vex_armor_trim_smithing_template", + "minecraft:wild_armor_trim_smithing_template", + "minecraft:flow_armor_trim_smithing_template", + "minecraft:raiser_armor_trim_smithing_template", + "minecraft:silence_armor_trim_smithing_template", + "minecraft:coast_armor_trim_smithing_template", + "minecraft:snout_armor_trim_smithing_template", + "minecraft:dune_armor_trim_smithing_template", + "minecraft:rib_armor_trim_smithing_template", + "minecraft:host_armor_trim_smithing_template", + "minecraft:bolt_armor_trim_smithing_template", + "minecraft:shaper_armor_trim_smithing_template", + "minecraft:eye_armor_trim_smithing_template", + "minecraft:spire_armor_trim_smithing_template", + "minecraft:sentry_armor_trim_smithing_template", + "minecraft:ward_armor_trim_smithing_template", + "minecraft:tide_armor_trim_smithing_template", + "minecraft:wayfinder_armor_trim_smithing_template" + ], + "minecraft:trimmable_armors": [ + "minecraft:netherite_boots", + "minecraft:chainmail_helmet", + "minecraft:leather_helmet", + "minecraft:leather_chestplate", + "minecraft:leather_leggings", + "minecraft:leather_boots", + "minecraft:chainmail_chestplate", + "minecraft:chainmail_leggings", + "minecraft:chainmail_boots", + "minecraft:iron_helmet", + "minecraft:iron_chestplate", + "minecraft:iron_leggings", + "minecraft:iron_boots", + "minecraft:diamond_helmet", + "minecraft:diamond_chestplate", + "minecraft:diamond_leggings", + "minecraft:diamond_boots", + "minecraft:golden_helmet", + "minecraft:golden_chestplate", + "minecraft:golden_leggings", + "minecraft:golden_boots", + "minecraft:turtle_helmet", + "minecraft:netherite_chestplate", + "minecraft:netherite_leggings", + "minecraft:netherite_helmet" + ], + "minecraft:vibration_damper": [ + "minecraft:black_carpet", + "minecraft:blue_carpet", + "minecraft:pink_carpet", + "minecraft:lime_carpet", + "minecraft:green_wool", + "minecraft:cyan_carpet", + "minecraft:orange_wool", + "minecraft:white_carpet", + "minecraft:purple_carpet", + "minecraft:yellow_carpet", + "minecraft:light_gray_wool", + "minecraft:magenta_carpet", + "minecraft:purple_wool", + "minecraft:gray_wool", + "minecraft:red_carpet", + "minecraft:brown_carpet", + "minecraft:light_blue_wool", + "minecraft:white_wool", + "minecraft:magenta_wool", + "minecraft:yellow_wool", + "minecraft:lime_wool", + "minecraft:pink_wool", + "minecraft:cyan_wool", + "minecraft:blue_wool", + "minecraft:brown_wool", + "minecraft:red_wool", + "minecraft:black_wool", + "minecraft:orange_carpet", + "minecraft:light_blue_carpet", + "minecraft:gray_carpet", + "minecraft:light_gray_carpet", + "minecraft:green_carpet" + ], + "minecraft:warped_stems": [ + "minecraft:stripped_warped_hyphae", + "minecraft:warped_hyphae", + "minecraft:warped_stem", + "minecraft:stripped_warped_stem" + ], + "minecraft:wooden_slabs": [ + "minecraft:birch_slab", + "minecraft:oak_slab", + "minecraft:spruce_slab", + "minecraft:bamboo_slab", + "minecraft:warped_slab", + "minecraft:mangrove_slab", + "minecraft:cherry_slab", + "minecraft:jungle_slab", + "minecraft:acacia_slab", + "minecraft:dark_oak_slab", + "minecraft:crimson_slab" + ], + "minecraft:wooden_tier": [ + "minecraft:wooden_pickaxe", + "minecraft:wooden_shovel", + "minecraft:wooden_sword", + "minecraft:wooden_axe", + "minecraft:wooden_hoe" + ], + "minecraft:wool": [ + "minecraft:green_wool", + "minecraft:orange_wool", + "minecraft:light_gray_wool", + "minecraft:purple_wool", + "minecraft:gray_wool", + "minecraft:light_blue_wool", + "minecraft:white_wool", + "minecraft:magenta_wool", + "minecraft:yellow_wool", + "minecraft:lime_wool", + "minecraft:pink_wool", + "minecraft:cyan_wool", + "minecraft:blue_wool", + "minecraft:brown_wool", + "minecraft:red_wool", + "minecraft:black_wool" + ] +} \ No newline at end of file diff --git a/core/src/main/resources/bedrock/item_tags.1_21_20.json b/core/src/main/resources/bedrock/item_tags.1_21_20.json new file mode 100644 index 000000000..faad0ed0c --- /dev/null +++ b/core/src/main/resources/bedrock/item_tags.1_21_20.json @@ -0,0 +1,806 @@ +{ + "minecraft:arrow": [ + "minecraft:arrow" + ], + "minecraft:banner": [ + "minecraft:banner" + ], + "minecraft:boat": [ + "minecraft:cherry_chest_boat", + "minecraft:oak_chest_boat", + "minecraft:mangrove_boat", + "minecraft:oak_boat", + "minecraft:birch_boat", + "minecraft:jungle_boat", + "minecraft:spruce_boat", + "minecraft:acacia_boat", + "minecraft:dark_oak_boat", + "minecraft:birch_chest_boat", + "minecraft:jungle_chest_boat", + "minecraft:spruce_chest_boat", + "minecraft:acacia_chest_boat", + "minecraft:dark_oak_chest_boat", + "minecraft:mangrove_chest_boat", + "minecraft:cherry_boat", + "minecraft:bamboo_raft", + "minecraft:bamboo_chest_raft" + ], + "minecraft:boats": [ + "minecraft:cherry_chest_boat", + "minecraft:oak_chest_boat", + "minecraft:mangrove_boat", + "minecraft:oak_boat", + "minecraft:birch_boat", + "minecraft:jungle_boat", + "minecraft:spruce_boat", + "minecraft:acacia_boat", + "minecraft:dark_oak_boat", + "minecraft:birch_chest_boat", + "minecraft:jungle_chest_boat", + "minecraft:spruce_chest_boat", + "minecraft:acacia_chest_boat", + "minecraft:dark_oak_chest_boat", + "minecraft:mangrove_chest_boat", + "minecraft:cherry_boat", + "minecraft:bamboo_raft", + "minecraft:bamboo_chest_raft" + ], + "minecraft:bookshelf_books": [ + "minecraft:written_book", + "minecraft:book", + "minecraft:writable_book", + "minecraft:enchanted_book" + ], + "minecraft:chainmail_tier": [ + "minecraft:chainmail_helmet", + "minecraft:chainmail_chestplate", + "minecraft:chainmail_leggings", + "minecraft:chainmail_boots" + ], + "minecraft:coals": [ + "minecraft:coal", + "minecraft:charcoal" + ], + "minecraft:crimson_stems": [ + "minecraft:stripped_crimson_stem", + "minecraft:crimson_hyphae", + "minecraft:crimson_stem", + "minecraft:stripped_crimson_hyphae" + ], + "minecraft:decorated_pot_sherds": [ + "minecraft:angler_pottery_sherd", + "minecraft:skull_pottery_sherd", + "minecraft:prize_pottery_sherd", + "minecraft:mourner_pottery_sherd", + "minecraft:arms_up_pottery_sherd", + "minecraft:burn_pottery_sherd", + "minecraft:snort_pottery_sherd", + "minecraft:brick", + "minecraft:heartbreak_pottery_sherd", + "minecraft:miner_pottery_sherd", + "minecraft:brewer_pottery_sherd", + "minecraft:plenty_pottery_sherd", + "minecraft:scrape_pottery_sherd", + "minecraft:howl_pottery_sherd", + "minecraft:explorer_pottery_sherd", + "minecraft:archer_pottery_sherd", + "minecraft:blade_pottery_sherd", + "minecraft:danger_pottery_sherd", + "minecraft:flow_pottery_sherd", + "minecraft:friend_pottery_sherd", + "minecraft:guster_pottery_sherd", + "minecraft:heart_pottery_sherd", + "minecraft:sheaf_pottery_sherd", + "minecraft:shelter_pottery_sherd" + ], + "minecraft:diamond_tier": [ + "minecraft:diamond_sword", + "minecraft:diamond_shovel", + "minecraft:diamond_pickaxe", + "minecraft:diamond_axe", + "minecraft:mace", + "minecraft:diamond_hoe", + "minecraft:diamond_helmet", + "minecraft:diamond_chestplate", + "minecraft:diamond_leggings", + "minecraft:diamond_boots" + ], + "minecraft:digger": [ + "minecraft:iron_pickaxe", + "minecraft:wooden_pickaxe", + "minecraft:wooden_shovel", + "minecraft:iron_axe", + "minecraft:iron_shovel", + "minecraft:stone_shovel", + "minecraft:wooden_axe", + "minecraft:stone_pickaxe", + "minecraft:stone_axe", + "minecraft:diamond_shovel", + "minecraft:diamond_pickaxe", + "minecraft:diamond_axe", + "minecraft:golden_shovel", + "minecraft:golden_pickaxe", + "minecraft:golden_axe", + "minecraft:wooden_hoe", + "minecraft:stone_hoe", + "minecraft:iron_hoe", + "minecraft:diamond_hoe", + "minecraft:golden_hoe", + "minecraft:netherite_pickaxe", + "minecraft:netherite_shovel", + "minecraft:netherite_axe", + "minecraft:netherite_hoe" + ], + "minecraft:door": [ + "minecraft:warped_door", + "minecraft:waxed_weathered_copper_door", + "minecraft:wooden_door", + "minecraft:iron_door", + "minecraft:mangrove_door", + "minecraft:exposed_copper_door", + "minecraft:bamboo_door", + "minecraft:weathered_copper_door", + "minecraft:jungle_door", + "minecraft:spruce_door", + "minecraft:birch_door", + "minecraft:acacia_door", + "minecraft:dark_oak_door", + "minecraft:crimson_door", + "minecraft:cherry_door", + "minecraft:copper_door", + "minecraft:oxidized_copper_door", + "minecraft:waxed_copper_door", + "minecraft:waxed_exposed_copper_door", + "minecraft:waxed_oxidized_copper_door" + ], + "minecraft:golden_tier": [ + "minecraft:golden_sword", + "minecraft:golden_shovel", + "minecraft:golden_pickaxe", + "minecraft:golden_axe", + "minecraft:golden_hoe", + "minecraft:golden_helmet", + "minecraft:golden_chestplate", + "minecraft:golden_leggings", + "minecraft:golden_boots" + ], + "minecraft:hanging_actor": [ + "minecraft:painting" + ], + "minecraft:hanging_sign": [ + "minecraft:mangrove_hanging_sign", + "minecraft:bamboo_hanging_sign", + "minecraft:spruce_hanging_sign", + "minecraft:birch_hanging_sign", + "minecraft:cherry_hanging_sign", + "minecraft:oak_hanging_sign", + "minecraft:jungle_hanging_sign", + "minecraft:acacia_hanging_sign", + "minecraft:dark_oak_hanging_sign", + "minecraft:crimson_hanging_sign", + "minecraft:warped_hanging_sign" + ], + "minecraft:horse_armor": [ + "minecraft:golden_horse_armor", + "minecraft:leather_horse_armor", + "minecraft:iron_horse_armor", + "minecraft:diamond_horse_armor" + ], + "minecraft:iron_tier": [ + "minecraft:iron_sword", + "minecraft:iron_pickaxe", + "minecraft:iron_axe", + "minecraft:iron_shovel", + "minecraft:iron_hoe", + "minecraft:iron_helmet", + "minecraft:iron_chestplate", + "minecraft:iron_leggings", + "minecraft:iron_boots" + ], + "minecraft:is_armor": [ + "minecraft:netherite_boots", + "minecraft:chainmail_helmet", + "minecraft:elytra", + "minecraft:leather_helmet", + "minecraft:leather_chestplate", + "minecraft:leather_leggings", + "minecraft:leather_boots", + "minecraft:chainmail_chestplate", + "minecraft:chainmail_leggings", + "minecraft:chainmail_boots", + "minecraft:iron_helmet", + "minecraft:iron_chestplate", + "minecraft:iron_leggings", + "minecraft:iron_boots", + "minecraft:diamond_helmet", + "minecraft:diamond_chestplate", + "minecraft:diamond_leggings", + "minecraft:diamond_boots", + "minecraft:golden_helmet", + "minecraft:golden_chestplate", + "minecraft:golden_leggings", + "minecraft:golden_boots", + "minecraft:turtle_helmet", + "minecraft:netherite_chestplate", + "minecraft:netherite_leggings", + "minecraft:netherite_helmet" + ], + "minecraft:is_axe": [ + "minecraft:iron_axe", + "minecraft:wooden_axe", + "minecraft:stone_axe", + "minecraft:diamond_axe", + "minecraft:golden_axe", + "minecraft:netherite_axe" + ], + "minecraft:is_cooked": [ + "minecraft:cooked_cod", + "minecraft:cooked_porkchop", + "minecraft:cooked_rabbit", + "minecraft:cooked_salmon", + "minecraft:cooked_beef", + "minecraft:cooked_chicken", + "minecraft:rabbit_stew", + "minecraft:cooked_mutton" + ], + "minecraft:is_fish": [ + "minecraft:cooked_cod", + "minecraft:cod", + "minecraft:salmon", + "minecraft:tropical_fish", + "minecraft:pufferfish", + "minecraft:cooked_salmon" + ], + "minecraft:is_food": [ + "minecraft:beetroot", + "minecraft:apple", + "minecraft:carrot", + "minecraft:chicken", + "minecraft:potato", + "minecraft:enchanted_golden_apple", + "minecraft:sweet_berries", + "minecraft:golden_carrot", + "minecraft:golden_apple", + "minecraft:rabbit", + "minecraft:cooked_porkchop", + "minecraft:mushroom_stew", + "minecraft:bread", + "minecraft:porkchop", + "minecraft:cookie", + "minecraft:cooked_rabbit", + "minecraft:beef", + "minecraft:dried_kelp", + "minecraft:beetroot_soup", + "minecraft:melon_slice", + "minecraft:cooked_beef", + "minecraft:rotten_flesh", + "minecraft:cooked_chicken", + "minecraft:baked_potato", + "minecraft:pumpkin_pie", + "minecraft:rabbit_stew", + "minecraft:cooked_mutton", + "minecraft:mutton" + ], + "minecraft:is_hoe": [ + "minecraft:wooden_hoe", + "minecraft:stone_hoe", + "minecraft:iron_hoe", + "minecraft:diamond_hoe", + "minecraft:golden_hoe", + "minecraft:netherite_hoe" + ], + "minecraft:is_meat": [ + "minecraft:chicken", + "minecraft:rabbit", + "minecraft:cooked_porkchop", + "minecraft:porkchop", + "minecraft:cooked_rabbit", + "minecraft:beef", + "minecraft:cooked_beef", + "minecraft:rotten_flesh", + "minecraft:cooked_chicken", + "minecraft:rabbit_stew", + "minecraft:cooked_mutton", + "minecraft:mutton" + ], + "minecraft:is_minecart": [ + "minecraft:command_block_minecart", + "minecraft:minecart", + "minecraft:chest_minecart", + "minecraft:tnt_minecart", + "minecraft:hopper_minecart" + ], + "minecraft:is_pickaxe": [ + "minecraft:iron_pickaxe", + "minecraft:wooden_pickaxe", + "minecraft:stone_pickaxe", + "minecraft:diamond_pickaxe", + "minecraft:golden_pickaxe", + "minecraft:netherite_pickaxe" + ], + "minecraft:is_shovel": [ + "minecraft:wooden_shovel", + "minecraft:iron_shovel", + "minecraft:stone_shovel", + "minecraft:diamond_shovel", + "minecraft:golden_shovel", + "minecraft:netherite_shovel" + ], + "minecraft:is_sword": [ + "minecraft:iron_sword", + "minecraft:stone_sword", + "minecraft:wooden_sword", + "minecraft:diamond_sword", + "minecraft:mace", + "minecraft:golden_sword", + "minecraft:netherite_sword" + ], + "minecraft:is_tool": [ + "minecraft:iron_sword", + "minecraft:iron_pickaxe", + "minecraft:wooden_pickaxe", + "minecraft:wooden_shovel", + "minecraft:stone_sword", + "minecraft:iron_axe", + "minecraft:iron_shovel", + "minecraft:stone_shovel", + "minecraft:wooden_sword", + "minecraft:wooden_axe", + "minecraft:stone_pickaxe", + "minecraft:stone_axe", + "minecraft:diamond_sword", + "minecraft:diamond_shovel", + "minecraft:diamond_pickaxe", + "minecraft:diamond_axe", + "minecraft:mace", + "minecraft:golden_sword", + "minecraft:golden_shovel", + "minecraft:golden_pickaxe", + "minecraft:golden_axe", + "minecraft:wooden_hoe", + "minecraft:stone_hoe", + "minecraft:iron_hoe", + "minecraft:diamond_hoe", + "minecraft:golden_hoe", + "minecraft:netherite_sword", + "minecraft:netherite_pickaxe", + "minecraft:netherite_shovel", + "minecraft:netherite_axe", + "minecraft:netherite_hoe" + ], + "minecraft:is_trident": [ + "minecraft:trident" + ], + "minecraft:leather_tier": [ + "minecraft:leather_helmet", + "minecraft:leather_chestplate", + "minecraft:leather_leggings", + "minecraft:leather_boots" + ], + "minecraft:lectern_books": [ + "minecraft:written_book", + "minecraft:writable_book" + ], + "minecraft:logs": [ + "minecraft:mangrove_wood", + "minecraft:spruce_wood", + "minecraft:stripped_cherry_wood", + "minecraft:stripped_crimson_stem", + "minecraft:stripped_spruce_wood", + "minecraft:spruce_log", + "minecraft:acacia_wood", + "minecraft:stripped_acacia_wood", + "minecraft:stripped_warped_hyphae", + "minecraft:acacia_log", + "minecraft:stripped_warped_stem", + "minecraft:oak_log", + "minecraft:birch_log", + "minecraft:jungle_log", + "minecraft:dark_oak_log", + "minecraft:jungle_wood", + "minecraft:stripped_jungle_wood", + "minecraft:oak_wood", + "minecraft:birch_wood", + "minecraft:dark_oak_wood", + "minecraft:stripped_oak_wood", + "minecraft:stripped_birch_wood", + "minecraft:stripped_dark_oak_wood", + "minecraft:stripped_oak_log", + "minecraft:stripped_dark_oak_log", + "minecraft:mangrove_log", + "minecraft:stripped_jungle_log", + "minecraft:stripped_mangrove_wood", + "minecraft:crimson_hyphae", + "minecraft:stripped_cherry_log", + "minecraft:stripped_birch_log", + "minecraft:stripped_acacia_log", + "minecraft:crimson_stem", + "minecraft:warped_hyphae", + "minecraft:stripped_spruce_log", + "minecraft:warped_stem", + "minecraft:stripped_crimson_hyphae", + "minecraft:cherry_wood", + "minecraft:cherry_log", + "minecraft:stripped_mangrove_log" + ], + "minecraft:logs_that_burn": [ + "minecraft:mangrove_wood", + "minecraft:spruce_wood", + "minecraft:stripped_cherry_wood", + "minecraft:stripped_spruce_wood", + "minecraft:spruce_log", + "minecraft:acacia_wood", + "minecraft:stripped_acacia_wood", + "minecraft:acacia_log", + "minecraft:oak_log", + "minecraft:birch_log", + "minecraft:jungle_log", + "minecraft:dark_oak_log", + "minecraft:jungle_wood", + "minecraft:stripped_jungle_wood", + "minecraft:oak_wood", + "minecraft:birch_wood", + "minecraft:dark_oak_wood", + "minecraft:stripped_oak_wood", + "minecraft:stripped_birch_wood", + "minecraft:stripped_dark_oak_wood", + "minecraft:stripped_oak_log", + "minecraft:stripped_dark_oak_log", + "minecraft:mangrove_log", + "minecraft:stripped_jungle_log", + "minecraft:stripped_mangrove_wood", + "minecraft:stripped_cherry_log", + "minecraft:stripped_birch_log", + "minecraft:stripped_acacia_log", + "minecraft:stripped_spruce_log", + "minecraft:cherry_wood", + "minecraft:cherry_log", + "minecraft:stripped_mangrove_log" + ], + "minecraft:mangrove_logs": [ + "minecraft:mangrove_wood", + "minecraft:mangrove_log", + "minecraft:stripped_mangrove_wood", + "minecraft:stripped_mangrove_log" + ], + "minecraft:music_disc": [ + "minecraft:music_disc_ward", + "minecraft:music_disc_strad", + "minecraft:music_disc_chirp", + "minecraft:music_disc_creator_music_box", + "minecraft:music_disc_mall", + "minecraft:music_disc_pigstep", + "minecraft:music_disc_wait", + "minecraft:music_disc_11", + "minecraft:music_disc_stal", + "minecraft:music_disc_13", + "minecraft:music_disc_cat", + "minecraft:music_disc_blocks", + "minecraft:music_disc_far", + "minecraft:music_disc_mellohi", + "minecraft:music_disc_otherside", + "minecraft:music_disc_5", + "minecraft:music_disc_relic", + "minecraft:music_disc_creator", + "minecraft:music_disc_precipice" + ], + "minecraft:netherite_tier": [ + "minecraft:netherite_boots", + "minecraft:netherite_sword", + "minecraft:netherite_chestplate", + "minecraft:netherite_pickaxe", + "minecraft:netherite_leggings", + "minecraft:netherite_shovel", + "minecraft:netherite_axe", + "minecraft:netherite_hoe", + "minecraft:netherite_helmet" + ], + "minecraft:planks": [ + "minecraft:spruce_planks", + "minecraft:oak_planks", + "minecraft:mangrove_planks", + "minecraft:dark_oak_planks", + "minecraft:birch_planks", + "minecraft:jungle_planks", + "minecraft:acacia_planks", + "minecraft:bamboo_planks", + "minecraft:warped_planks", + "minecraft:crimson_planks", + "minecraft:cherry_planks" + ], + "minecraft:sand": [ + "minecraft:sand", + "minecraft:red_sand" + ], + "minecraft:sign": [ + "minecraft:bamboo_sign", + "minecraft:mangrove_hanging_sign", + "minecraft:cherry_sign", + "minecraft:oak_sign", + "minecraft:bamboo_hanging_sign", + "minecraft:warped_sign", + "minecraft:spruce_sign", + "minecraft:spruce_hanging_sign", + "minecraft:acacia_sign", + "minecraft:birch_hanging_sign", + "minecraft:birch_sign", + "minecraft:jungle_sign", + "minecraft:dark_oak_sign", + "minecraft:mangrove_sign", + "minecraft:crimson_sign", + "minecraft:cherry_hanging_sign", + "minecraft:oak_hanging_sign", + "minecraft:jungle_hanging_sign", + "minecraft:acacia_hanging_sign", + "minecraft:dark_oak_hanging_sign", + "minecraft:crimson_hanging_sign", + "minecraft:warped_hanging_sign" + ], + "minecraft:soul_fire_base_blocks": [ + "minecraft:soul_soil", + "minecraft:soul_sand" + ], + "minecraft:spawn_egg": [ + "minecraft:enderman_spawn_egg", + "minecraft:strider_spawn_egg", + "minecraft:ravager_spawn_egg", + "minecraft:slime_spawn_egg", + "minecraft:glow_squid_spawn_egg", + "minecraft:pillager_spawn_egg", + "minecraft:blaze_spawn_egg", + "minecraft:witch_spawn_egg", + "minecraft:horse_spawn_egg", + "minecraft:polar_bear_spawn_egg", + "minecraft:zoglin_spawn_egg", + "minecraft:stray_spawn_egg", + "minecraft:zombie_pigman_spawn_egg", + "minecraft:snow_golem_spawn_egg", + "minecraft:panda_spawn_egg", + "minecraft:axolotl_spawn_egg", + "minecraft:agent_spawn_egg", + "minecraft:shulker_spawn_egg", + "minecraft:vindicator_spawn_egg", + "minecraft:evoker_spawn_egg", + "minecraft:parrot_spawn_egg", + "minecraft:wolf_spawn_egg", + "minecraft:elder_guardian_spawn_egg", + "minecraft:silverfish_spawn_egg", + "minecraft:tadpole_spawn_egg", + "minecraft:cow_spawn_egg", + "minecraft:bogged_spawn_egg", + "minecraft:ocelot_spawn_egg", + "minecraft:bee_spawn_egg", + "minecraft:piglin_brute_spawn_egg", + "minecraft:rabbit_spawn_egg", + "minecraft:camel_spawn_egg", + "minecraft:creeper_spawn_egg", + "minecraft:drowned_spawn_egg", + "minecraft:chicken_spawn_egg", + "minecraft:pig_spawn_egg", + "minecraft:sheep_spawn_egg", + "minecraft:mooshroom_spawn_egg", + "minecraft:skeleton_spawn_egg", + "minecraft:spider_spawn_egg", + "minecraft:zombie_spawn_egg", + "minecraft:villager_spawn_egg", + "minecraft:squid_spawn_egg", + "minecraft:bat_spawn_egg", + "minecraft:ghast_spawn_egg", + "minecraft:magma_cube_spawn_egg", + "minecraft:cave_spider_spawn_egg", + "minecraft:endermite_spawn_egg", + "minecraft:guardian_spawn_egg", + "minecraft:husk_spawn_egg", + "minecraft:piglin_spawn_egg", + "minecraft:wither_skeleton_spawn_egg", + "minecraft:donkey_spawn_egg", + "minecraft:mule_spawn_egg", + "minecraft:skeleton_horse_spawn_egg", + "minecraft:zombie_horse_spawn_egg", + "minecraft:npc_spawn_egg", + "minecraft:breeze_spawn_egg", + "minecraft:llama_spawn_egg", + "minecraft:vex_spawn_egg", + "minecraft:warden_spawn_egg", + "minecraft:zombie_villager_spawn_egg", + "minecraft:tropical_fish_spawn_egg", + "minecraft:cod_spawn_egg", + "minecraft:pufferfish_spawn_egg", + "minecraft:salmon_spawn_egg", + "minecraft:dolphin_spawn_egg", + "minecraft:turtle_spawn_egg", + "minecraft:phantom_spawn_egg", + "minecraft:cat_spawn_egg", + "minecraft:fox_spawn_egg", + "minecraft:wandering_trader_spawn_egg", + "minecraft:hoglin_spawn_egg", + "minecraft:sniffer_spawn_egg", + "minecraft:goat_spawn_egg", + "minecraft:iron_golem_spawn_egg", + "minecraft:ender_dragon_spawn_egg", + "minecraft:wither_spawn_egg", + "minecraft:frog_spawn_egg", + "minecraft:allay_spawn_egg", + "minecraft:trader_llama_spawn_egg", + "minecraft:armadillo_spawn_egg", + "minecraft:spawn_egg" + ], + "minecraft:stone_bricks": [ + "minecraft:mossy_stone_bricks", + "minecraft:stone_bricks", + "minecraft:cracked_stone_bricks", + "minecraft:chiseled_stone_bricks" + ], + "minecraft:stone_crafting_materials": [ + "minecraft:cobblestone", + "minecraft:cobbled_deepslate", + "minecraft:blackstone" + ], + "minecraft:stone_tier": [ + "minecraft:stone_sword", + "minecraft:stone_shovel", + "minecraft:stone_pickaxe", + "minecraft:stone_axe", + "minecraft:stone_hoe" + ], + "minecraft:stone_tool_materials": [ + "minecraft:cobblestone", + "minecraft:cobbled_deepslate", + "minecraft:blackstone" + ], + "minecraft:transform_materials": [ + "minecraft:netherite_ingot" + ], + "minecraft:transform_templates": [ + "minecraft:netherite_upgrade_smithing_template" + ], + "minecraft:transformable_items": [ + "minecraft:diamond_sword", + "minecraft:diamond_shovel", + "minecraft:diamond_pickaxe", + "minecraft:diamond_axe", + "minecraft:diamond_hoe", + "minecraft:diamond_helmet", + "minecraft:diamond_chestplate", + "minecraft:diamond_leggings", + "minecraft:diamond_boots", + "minecraft:golden_boots" + ], + "minecraft:trim_materials": [ + "minecraft:gold_ingot", + "minecraft:iron_ingot", + "minecraft:diamond", + "minecraft:redstone", + "minecraft:netherite_ingot", + "minecraft:lapis_lazuli", + "minecraft:quartz", + "minecraft:copper_ingot", + "minecraft:emerald", + "minecraft:amethyst_shard" + ], + "minecraft:trim_templates": [ + "minecraft:vex_armor_trim_smithing_template", + "minecraft:wild_armor_trim_smithing_template", + "minecraft:flow_armor_trim_smithing_template", + "minecraft:raiser_armor_trim_smithing_template", + "minecraft:silence_armor_trim_smithing_template", + "minecraft:coast_armor_trim_smithing_template", + "minecraft:snout_armor_trim_smithing_template", + "minecraft:dune_armor_trim_smithing_template", + "minecraft:rib_armor_trim_smithing_template", + "minecraft:host_armor_trim_smithing_template", + "minecraft:bolt_armor_trim_smithing_template", + "minecraft:shaper_armor_trim_smithing_template", + "minecraft:eye_armor_trim_smithing_template", + "minecraft:spire_armor_trim_smithing_template", + "minecraft:sentry_armor_trim_smithing_template", + "minecraft:ward_armor_trim_smithing_template", + "minecraft:tide_armor_trim_smithing_template", + "minecraft:wayfinder_armor_trim_smithing_template" + ], + "minecraft:trimmable_armors": [ + "minecraft:netherite_boots", + "minecraft:chainmail_helmet", + "minecraft:leather_helmet", + "minecraft:leather_chestplate", + "minecraft:leather_leggings", + "minecraft:leather_boots", + "minecraft:chainmail_chestplate", + "minecraft:chainmail_leggings", + "minecraft:chainmail_boots", + "minecraft:iron_helmet", + "minecraft:iron_chestplate", + "minecraft:iron_leggings", + "minecraft:iron_boots", + "minecraft:diamond_helmet", + "minecraft:diamond_chestplate", + "minecraft:diamond_leggings", + "minecraft:diamond_boots", + "minecraft:golden_helmet", + "minecraft:golden_chestplate", + "minecraft:golden_leggings", + "minecraft:golden_boots", + "minecraft:turtle_helmet", + "minecraft:netherite_chestplate", + "minecraft:netherite_leggings", + "minecraft:netherite_helmet" + ], + "minecraft:vibration_damper": [ + "minecraft:black_carpet", + "minecraft:blue_carpet", + "minecraft:pink_carpet", + "minecraft:lime_carpet", + "minecraft:green_wool", + "minecraft:cyan_carpet", + "minecraft:orange_wool", + "minecraft:white_carpet", + "minecraft:purple_carpet", + "minecraft:yellow_carpet", + "minecraft:light_gray_wool", + "minecraft:magenta_carpet", + "minecraft:purple_wool", + "minecraft:gray_wool", + "minecraft:red_carpet", + "minecraft:brown_carpet", + "minecraft:light_blue_wool", + "minecraft:white_wool", + "minecraft:magenta_wool", + "minecraft:yellow_wool", + "minecraft:lime_wool", + "minecraft:pink_wool", + "minecraft:cyan_wool", + "minecraft:blue_wool", + "minecraft:brown_wool", + "minecraft:red_wool", + "minecraft:black_wool", + "minecraft:orange_carpet", + "minecraft:light_blue_carpet", + "minecraft:gray_carpet", + "minecraft:light_gray_carpet", + "minecraft:green_carpet" + ], + "minecraft:warped_stems": [ + "minecraft:stripped_warped_hyphae", + "minecraft:stripped_warped_stem", + "minecraft:warped_hyphae", + "minecraft:warped_stem" + ], + "minecraft:wooden_slabs": [ + "minecraft:birch_slab", + "minecraft:oak_slab", + "minecraft:spruce_slab", + "minecraft:bamboo_slab", + "minecraft:warped_slab", + "minecraft:mangrove_slab", + "minecraft:cherry_slab", + "minecraft:jungle_slab", + "minecraft:acacia_slab", + "minecraft:dark_oak_slab", + "minecraft:crimson_slab" + ], + "minecraft:wooden_tier": [ + "minecraft:wooden_pickaxe", + "minecraft:wooden_shovel", + "minecraft:wooden_sword", + "minecraft:wooden_axe", + "minecraft:wooden_hoe" + ], + "minecraft:wool": [ + "minecraft:green_wool", + "minecraft:orange_wool", + "minecraft:light_gray_wool", + "minecraft:purple_wool", + "minecraft:gray_wool", + "minecraft:light_blue_wool", + "minecraft:white_wool", + "minecraft:magenta_wool", + "minecraft:yellow_wool", + "minecraft:lime_wool", + "minecraft:pink_wool", + "minecraft:cyan_wool", + "minecraft:blue_wool", + "minecraft:brown_wool", + "minecraft:red_wool", + "minecraft:black_wool" + ] +} \ No newline at end of file diff --git a/core/src/main/resources/bedrock/item_tags.1_21_30.json b/core/src/main/resources/bedrock/item_tags.1_21_30.json new file mode 100644 index 000000000..cff3f2556 --- /dev/null +++ b/core/src/main/resources/bedrock/item_tags.1_21_30.json @@ -0,0 +1,806 @@ +{ + "minecraft:arrow": [ + "minecraft:arrow" + ], + "minecraft:banner": [ + "minecraft:banner" + ], + "minecraft:boat": [ + "minecraft:cherry_chest_boat", + "minecraft:oak_chest_boat", + "minecraft:mangrove_boat", + "minecraft:oak_boat", + "minecraft:birch_boat", + "minecraft:jungle_boat", + "minecraft:spruce_boat", + "minecraft:acacia_boat", + "minecraft:dark_oak_boat", + "minecraft:birch_chest_boat", + "minecraft:jungle_chest_boat", + "minecraft:spruce_chest_boat", + "minecraft:acacia_chest_boat", + "minecraft:dark_oak_chest_boat", + "minecraft:mangrove_chest_boat", + "minecraft:cherry_boat", + "minecraft:bamboo_raft", + "minecraft:bamboo_chest_raft" + ], + "minecraft:boats": [ + "minecraft:cherry_chest_boat", + "minecraft:oak_chest_boat", + "minecraft:mangrove_boat", + "minecraft:oak_boat", + "minecraft:birch_boat", + "minecraft:jungle_boat", + "minecraft:spruce_boat", + "minecraft:acacia_boat", + "minecraft:dark_oak_boat", + "minecraft:birch_chest_boat", + "minecraft:jungle_chest_boat", + "minecraft:spruce_chest_boat", + "minecraft:acacia_chest_boat", + "minecraft:dark_oak_chest_boat", + "minecraft:mangrove_chest_boat", + "minecraft:cherry_boat", + "minecraft:bamboo_raft", + "minecraft:bamboo_chest_raft" + ], + "minecraft:bookshelf_books": [ + "minecraft:written_book", + "minecraft:book", + "minecraft:writable_book", + "minecraft:enchanted_book" + ], + "minecraft:chainmail_tier": [ + "minecraft:chainmail_helmet", + "minecraft:chainmail_chestplate", + "minecraft:chainmail_leggings", + "minecraft:chainmail_boots" + ], + "minecraft:coals": [ + "minecraft:coal", + "minecraft:charcoal" + ], + "minecraft:crimson_stems": [ + "minecraft:stripped_crimson_stem", + "minecraft:crimson_hyphae", + "minecraft:crimson_stem", + "minecraft:stripped_crimson_hyphae" + ], + "minecraft:decorated_pot_sherds": [ + "minecraft:angler_pottery_sherd", + "minecraft:skull_pottery_sherd", + "minecraft:prize_pottery_sherd", + "minecraft:mourner_pottery_sherd", + "minecraft:arms_up_pottery_sherd", + "minecraft:burn_pottery_sherd", + "minecraft:snort_pottery_sherd", + "minecraft:brick", + "minecraft:heartbreak_pottery_sherd", + "minecraft:miner_pottery_sherd", + "minecraft:brewer_pottery_sherd", + "minecraft:plenty_pottery_sherd", + "minecraft:scrape_pottery_sherd", + "minecraft:howl_pottery_sherd", + "minecraft:explorer_pottery_sherd", + "minecraft:archer_pottery_sherd", + "minecraft:blade_pottery_sherd", + "minecraft:danger_pottery_sherd", + "minecraft:flow_pottery_sherd", + "minecraft:friend_pottery_sherd", + "minecraft:guster_pottery_sherd", + "minecraft:heart_pottery_sherd", + "minecraft:sheaf_pottery_sherd", + "minecraft:shelter_pottery_sherd" + ], + "minecraft:diamond_tier": [ + "minecraft:diamond_sword", + "minecraft:diamond_shovel", + "minecraft:diamond_pickaxe", + "minecraft:diamond_axe", + "minecraft:mace", + "minecraft:diamond_hoe", + "minecraft:diamond_helmet", + "minecraft:diamond_chestplate", + "minecraft:diamond_leggings", + "minecraft:diamond_boots" + ], + "minecraft:digger": [ + "minecraft:iron_pickaxe", + "minecraft:wooden_pickaxe", + "minecraft:wooden_shovel", + "minecraft:iron_axe", + "minecraft:iron_shovel", + "minecraft:stone_shovel", + "minecraft:wooden_axe", + "minecraft:stone_pickaxe", + "minecraft:stone_axe", + "minecraft:diamond_shovel", + "minecraft:diamond_pickaxe", + "minecraft:diamond_axe", + "minecraft:golden_shovel", + "minecraft:golden_pickaxe", + "minecraft:golden_axe", + "minecraft:wooden_hoe", + "minecraft:stone_hoe", + "minecraft:iron_hoe", + "minecraft:diamond_hoe", + "minecraft:golden_hoe", + "minecraft:netherite_pickaxe", + "minecraft:netherite_shovel", + "minecraft:netherite_axe", + "minecraft:netherite_hoe" + ], + "minecraft:door": [ + "minecraft:warped_door", + "minecraft:waxed_weathered_copper_door", + "minecraft:wooden_door", + "minecraft:iron_door", + "minecraft:mangrove_door", + "minecraft:exposed_copper_door", + "minecraft:bamboo_door", + "minecraft:weathered_copper_door", + "minecraft:jungle_door", + "minecraft:spruce_door", + "minecraft:birch_door", + "minecraft:acacia_door", + "minecraft:dark_oak_door", + "minecraft:crimson_door", + "minecraft:cherry_door", + "minecraft:copper_door", + "minecraft:oxidized_copper_door", + "minecraft:waxed_copper_door", + "minecraft:waxed_exposed_copper_door", + "minecraft:waxed_oxidized_copper_door" + ], + "minecraft:golden_tier": [ + "minecraft:golden_sword", + "minecraft:golden_shovel", + "minecraft:golden_pickaxe", + "minecraft:golden_axe", + "minecraft:golden_hoe", + "minecraft:golden_helmet", + "minecraft:golden_chestplate", + "minecraft:golden_leggings", + "minecraft:golden_boots" + ], + "minecraft:hanging_actor": [ + "minecraft:painting" + ], + "minecraft:hanging_sign": [ + "minecraft:mangrove_hanging_sign", + "minecraft:bamboo_hanging_sign", + "minecraft:spruce_hanging_sign", + "minecraft:birch_hanging_sign", + "minecraft:cherry_hanging_sign", + "minecraft:oak_hanging_sign", + "minecraft:jungle_hanging_sign", + "minecraft:acacia_hanging_sign", + "minecraft:dark_oak_hanging_sign", + "minecraft:crimson_hanging_sign", + "minecraft:warped_hanging_sign" + ], + "minecraft:horse_armor": [ + "minecraft:golden_horse_armor", + "minecraft:leather_horse_armor", + "minecraft:iron_horse_armor", + "minecraft:diamond_horse_armor" + ], + "minecraft:iron_tier": [ + "minecraft:iron_sword", + "minecraft:iron_pickaxe", + "minecraft:iron_axe", + "minecraft:iron_shovel", + "minecraft:iron_hoe", + "minecraft:iron_helmet", + "minecraft:iron_chestplate", + "minecraft:iron_leggings", + "minecraft:iron_boots" + ], + "minecraft:is_armor": [ + "minecraft:netherite_boots", + "minecraft:chainmail_helmet", + "minecraft:elytra", + "minecraft:leather_helmet", + "minecraft:leather_chestplate", + "minecraft:leather_leggings", + "minecraft:leather_boots", + "minecraft:chainmail_chestplate", + "minecraft:chainmail_leggings", + "minecraft:chainmail_boots", + "minecraft:iron_helmet", + "minecraft:iron_chestplate", + "minecraft:iron_leggings", + "minecraft:iron_boots", + "minecraft:diamond_helmet", + "minecraft:diamond_chestplate", + "minecraft:diamond_leggings", + "minecraft:diamond_boots", + "minecraft:golden_helmet", + "minecraft:golden_chestplate", + "minecraft:golden_leggings", + "minecraft:golden_boots", + "minecraft:turtle_helmet", + "minecraft:netherite_chestplate", + "minecraft:netherite_leggings", + "minecraft:netherite_helmet" + ], + "minecraft:is_axe": [ + "minecraft:iron_axe", + "minecraft:wooden_axe", + "minecraft:stone_axe", + "minecraft:diamond_axe", + "minecraft:golden_axe", + "minecraft:netherite_axe" + ], + "minecraft:is_cooked": [ + "minecraft:cooked_cod", + "minecraft:cooked_porkchop", + "minecraft:cooked_rabbit", + "minecraft:cooked_salmon", + "minecraft:cooked_beef", + "minecraft:cooked_chicken", + "minecraft:rabbit_stew", + "minecraft:cooked_mutton" + ], + "minecraft:is_fish": [ + "minecraft:cooked_cod", + "minecraft:cod", + "minecraft:salmon", + "minecraft:tropical_fish", + "minecraft:pufferfish", + "minecraft:cooked_salmon" + ], + "minecraft:is_food": [ + "minecraft:golden_carrot", + "minecraft:carrot", + "minecraft:chicken", + "minecraft:apple", + "minecraft:beetroot", + "minecraft:potato", + "minecraft:enchanted_golden_apple", + "minecraft:sweet_berries", + "minecraft:golden_apple", + "minecraft:rabbit", + "minecraft:cooked_porkchop", + "minecraft:mushroom_stew", + "minecraft:bread", + "minecraft:porkchop", + "minecraft:cookie", + "minecraft:cooked_rabbit", + "minecraft:beef", + "minecraft:dried_kelp", + "minecraft:beetroot_soup", + "minecraft:melon_slice", + "minecraft:cooked_beef", + "minecraft:rotten_flesh", + "minecraft:cooked_chicken", + "minecraft:baked_potato", + "minecraft:pumpkin_pie", + "minecraft:rabbit_stew", + "minecraft:cooked_mutton", + "minecraft:mutton" + ], + "minecraft:is_hoe": [ + "minecraft:wooden_hoe", + "minecraft:stone_hoe", + "minecraft:iron_hoe", + "minecraft:diamond_hoe", + "minecraft:golden_hoe", + "minecraft:netherite_hoe" + ], + "minecraft:is_meat": [ + "minecraft:chicken", + "minecraft:rabbit", + "minecraft:cooked_porkchop", + "minecraft:porkchop", + "minecraft:cooked_rabbit", + "minecraft:beef", + "minecraft:cooked_beef", + "minecraft:rotten_flesh", + "minecraft:cooked_chicken", + "minecraft:rabbit_stew", + "minecraft:cooked_mutton", + "minecraft:mutton" + ], + "minecraft:is_minecart": [ + "minecraft:command_block_minecart", + "minecraft:minecart", + "minecraft:chest_minecart", + "minecraft:tnt_minecart", + "minecraft:hopper_minecart" + ], + "minecraft:is_pickaxe": [ + "minecraft:iron_pickaxe", + "minecraft:wooden_pickaxe", + "minecraft:stone_pickaxe", + "minecraft:diamond_pickaxe", + "minecraft:golden_pickaxe", + "minecraft:netherite_pickaxe" + ], + "minecraft:is_shovel": [ + "minecraft:wooden_shovel", + "minecraft:iron_shovel", + "minecraft:stone_shovel", + "minecraft:diamond_shovel", + "minecraft:golden_shovel", + "minecraft:netherite_shovel" + ], + "minecraft:is_sword": [ + "minecraft:iron_sword", + "minecraft:stone_sword", + "minecraft:wooden_sword", + "minecraft:diamond_sword", + "minecraft:mace", + "minecraft:golden_sword", + "minecraft:netherite_sword" + ], + "minecraft:is_tool": [ + "minecraft:iron_sword", + "minecraft:iron_pickaxe", + "minecraft:wooden_pickaxe", + "minecraft:wooden_shovel", + "minecraft:stone_sword", + "minecraft:iron_axe", + "minecraft:iron_shovel", + "minecraft:stone_shovel", + "minecraft:wooden_sword", + "minecraft:wooden_axe", + "minecraft:stone_pickaxe", + "minecraft:stone_axe", + "minecraft:diamond_sword", + "minecraft:diamond_shovel", + "minecraft:diamond_pickaxe", + "minecraft:diamond_axe", + "minecraft:mace", + "minecraft:golden_sword", + "minecraft:golden_shovel", + "minecraft:golden_pickaxe", + "minecraft:golden_axe", + "minecraft:wooden_hoe", + "minecraft:stone_hoe", + "minecraft:iron_hoe", + "minecraft:diamond_hoe", + "minecraft:golden_hoe", + "minecraft:netherite_sword", + "minecraft:netherite_pickaxe", + "minecraft:netherite_shovel", + "minecraft:netherite_axe", + "minecraft:netherite_hoe" + ], + "minecraft:is_trident": [ + "minecraft:trident" + ], + "minecraft:leather_tier": [ + "minecraft:leather_helmet", + "minecraft:leather_chestplate", + "minecraft:leather_leggings", + "minecraft:leather_boots" + ], + "minecraft:lectern_books": [ + "minecraft:written_book", + "minecraft:writable_book" + ], + "minecraft:logs": [ + "minecraft:mangrove_wood", + "minecraft:spruce_wood", + "minecraft:stripped_cherry_wood", + "minecraft:stripped_crimson_stem", + "minecraft:stripped_spruce_wood", + "minecraft:spruce_log", + "minecraft:acacia_wood", + "minecraft:stripped_acacia_wood", + "minecraft:stripped_warped_hyphae", + "minecraft:acacia_log", + "minecraft:stripped_warped_stem", + "minecraft:oak_log", + "minecraft:birch_log", + "minecraft:jungle_log", + "minecraft:dark_oak_log", + "minecraft:jungle_wood", + "minecraft:stripped_jungle_wood", + "minecraft:oak_wood", + "minecraft:birch_wood", + "minecraft:dark_oak_wood", + "minecraft:stripped_oak_wood", + "minecraft:stripped_birch_wood", + "minecraft:stripped_dark_oak_wood", + "minecraft:stripped_oak_log", + "minecraft:stripped_dark_oak_log", + "minecraft:mangrove_log", + "minecraft:stripped_jungle_log", + "minecraft:stripped_mangrove_wood", + "minecraft:crimson_hyphae", + "minecraft:stripped_cherry_log", + "minecraft:stripped_birch_log", + "minecraft:stripped_acacia_log", + "minecraft:crimson_stem", + "minecraft:warped_hyphae", + "minecraft:stripped_spruce_log", + "minecraft:warped_stem", + "minecraft:stripped_crimson_hyphae", + "minecraft:cherry_wood", + "minecraft:cherry_log", + "minecraft:stripped_mangrove_log" + ], + "minecraft:logs_that_burn": [ + "minecraft:mangrove_wood", + "minecraft:spruce_wood", + "minecraft:stripped_cherry_wood", + "minecraft:stripped_spruce_wood", + "minecraft:spruce_log", + "minecraft:acacia_wood", + "minecraft:stripped_acacia_wood", + "minecraft:acacia_log", + "minecraft:oak_log", + "minecraft:birch_log", + "minecraft:jungle_log", + "minecraft:dark_oak_log", + "minecraft:jungle_wood", + "minecraft:stripped_jungle_wood", + "minecraft:oak_wood", + "minecraft:birch_wood", + "minecraft:dark_oak_wood", + "minecraft:stripped_oak_wood", + "minecraft:stripped_birch_wood", + "minecraft:stripped_dark_oak_wood", + "minecraft:stripped_oak_log", + "minecraft:stripped_dark_oak_log", + "minecraft:mangrove_log", + "minecraft:stripped_jungle_log", + "minecraft:stripped_mangrove_wood", + "minecraft:stripped_cherry_log", + "minecraft:stripped_birch_log", + "minecraft:stripped_acacia_log", + "minecraft:stripped_spruce_log", + "minecraft:cherry_wood", + "minecraft:cherry_log", + "minecraft:stripped_mangrove_log" + ], + "minecraft:mangrove_logs": [ + "minecraft:mangrove_wood", + "minecraft:mangrove_log", + "minecraft:stripped_mangrove_wood", + "minecraft:stripped_mangrove_log" + ], + "minecraft:music_disc": [ + "minecraft:music_disc_ward", + "minecraft:music_disc_strad", + "minecraft:music_disc_chirp", + "minecraft:music_disc_creator_music_box", + "minecraft:music_disc_mall", + "minecraft:music_disc_pigstep", + "minecraft:music_disc_wait", + "minecraft:music_disc_11", + "minecraft:music_disc_stal", + "minecraft:music_disc_13", + "minecraft:music_disc_cat", + "minecraft:music_disc_blocks", + "minecraft:music_disc_far", + "minecraft:music_disc_mellohi", + "minecraft:music_disc_otherside", + "minecraft:music_disc_5", + "minecraft:music_disc_relic", + "minecraft:music_disc_creator", + "minecraft:music_disc_precipice" + ], + "minecraft:netherite_tier": [ + "minecraft:netherite_boots", + "minecraft:netherite_sword", + "minecraft:netherite_chestplate", + "minecraft:netherite_pickaxe", + "minecraft:netherite_leggings", + "minecraft:netherite_shovel", + "minecraft:netherite_axe", + "minecraft:netherite_hoe", + "minecraft:netherite_helmet" + ], + "minecraft:planks": [ + "minecraft:spruce_planks", + "minecraft:oak_planks", + "minecraft:mangrove_planks", + "minecraft:dark_oak_planks", + "minecraft:birch_planks", + "minecraft:jungle_planks", + "minecraft:acacia_planks", + "minecraft:bamboo_planks", + "minecraft:warped_planks", + "minecraft:crimson_planks", + "minecraft:cherry_planks" + ], + "minecraft:sand": [ + "minecraft:sand", + "minecraft:red_sand" + ], + "minecraft:sign": [ + "minecraft:bamboo_sign", + "minecraft:mangrove_hanging_sign", + "minecraft:cherry_sign", + "minecraft:oak_sign", + "minecraft:bamboo_hanging_sign", + "minecraft:warped_sign", + "minecraft:spruce_sign", + "minecraft:spruce_hanging_sign", + "minecraft:acacia_sign", + "minecraft:birch_hanging_sign", + "minecraft:birch_sign", + "minecraft:jungle_sign", + "minecraft:dark_oak_sign", + "minecraft:mangrove_sign", + "minecraft:crimson_sign", + "minecraft:cherry_hanging_sign", + "minecraft:oak_hanging_sign", + "minecraft:jungle_hanging_sign", + "minecraft:acacia_hanging_sign", + "minecraft:dark_oak_hanging_sign", + "minecraft:crimson_hanging_sign", + "minecraft:warped_hanging_sign" + ], + "minecraft:soul_fire_base_blocks": [ + "minecraft:soul_soil", + "minecraft:soul_sand" + ], + "minecraft:spawn_egg": [ + "minecraft:enderman_spawn_egg", + "minecraft:strider_spawn_egg", + "minecraft:ravager_spawn_egg", + "minecraft:slime_spawn_egg", + "minecraft:glow_squid_spawn_egg", + "minecraft:pillager_spawn_egg", + "minecraft:blaze_spawn_egg", + "minecraft:witch_spawn_egg", + "minecraft:horse_spawn_egg", + "minecraft:polar_bear_spawn_egg", + "minecraft:zoglin_spawn_egg", + "minecraft:stray_spawn_egg", + "minecraft:zombie_pigman_spawn_egg", + "minecraft:snow_golem_spawn_egg", + "minecraft:panda_spawn_egg", + "minecraft:axolotl_spawn_egg", + "minecraft:agent_spawn_egg", + "minecraft:shulker_spawn_egg", + "minecraft:vindicator_spawn_egg", + "minecraft:evoker_spawn_egg", + "minecraft:parrot_spawn_egg", + "minecraft:wolf_spawn_egg", + "minecraft:sheep_spawn_egg", + "minecraft:elder_guardian_spawn_egg", + "minecraft:silverfish_spawn_egg", + "minecraft:tadpole_spawn_egg", + "minecraft:cow_spawn_egg", + "minecraft:bogged_spawn_egg", + "minecraft:ocelot_spawn_egg", + "minecraft:bee_spawn_egg", + "minecraft:piglin_brute_spawn_egg", + "minecraft:rabbit_spawn_egg", + "minecraft:camel_spawn_egg", + "minecraft:creeper_spawn_egg", + "minecraft:drowned_spawn_egg", + "minecraft:chicken_spawn_egg", + "minecraft:pig_spawn_egg", + "minecraft:mooshroom_spawn_egg", + "minecraft:skeleton_spawn_egg", + "minecraft:spider_spawn_egg", + "minecraft:zombie_spawn_egg", + "minecraft:villager_spawn_egg", + "minecraft:squid_spawn_egg", + "minecraft:bat_spawn_egg", + "minecraft:ghast_spawn_egg", + "minecraft:magma_cube_spawn_egg", + "minecraft:cave_spider_spawn_egg", + "minecraft:endermite_spawn_egg", + "minecraft:guardian_spawn_egg", + "minecraft:husk_spawn_egg", + "minecraft:piglin_spawn_egg", + "minecraft:wither_skeleton_spawn_egg", + "minecraft:donkey_spawn_egg", + "minecraft:mule_spawn_egg", + "minecraft:skeleton_horse_spawn_egg", + "minecraft:zombie_horse_spawn_egg", + "minecraft:npc_spawn_egg", + "minecraft:breeze_spawn_egg", + "minecraft:llama_spawn_egg", + "minecraft:vex_spawn_egg", + "minecraft:warden_spawn_egg", + "minecraft:zombie_villager_spawn_egg", + "minecraft:tropical_fish_spawn_egg", + "minecraft:cod_spawn_egg", + "minecraft:pufferfish_spawn_egg", + "minecraft:salmon_spawn_egg", + "minecraft:dolphin_spawn_egg", + "minecraft:turtle_spawn_egg", + "minecraft:phantom_spawn_egg", + "minecraft:cat_spawn_egg", + "minecraft:fox_spawn_egg", + "minecraft:wandering_trader_spawn_egg", + "minecraft:hoglin_spawn_egg", + "minecraft:sniffer_spawn_egg", + "minecraft:goat_spawn_egg", + "minecraft:iron_golem_spawn_egg", + "minecraft:ender_dragon_spawn_egg", + "minecraft:wither_spawn_egg", + "minecraft:frog_spawn_egg", + "minecraft:allay_spawn_egg", + "minecraft:trader_llama_spawn_egg", + "minecraft:armadillo_spawn_egg", + "minecraft:spawn_egg" + ], + "minecraft:stone_bricks": [ + "minecraft:mossy_stone_bricks", + "minecraft:stone_bricks", + "minecraft:cracked_stone_bricks", + "minecraft:chiseled_stone_bricks" + ], + "minecraft:stone_crafting_materials": [ + "minecraft:cobblestone", + "minecraft:cobbled_deepslate", + "minecraft:blackstone" + ], + "minecraft:stone_tier": [ + "minecraft:stone_sword", + "minecraft:stone_shovel", + "minecraft:stone_pickaxe", + "minecraft:stone_axe", + "minecraft:stone_hoe" + ], + "minecraft:stone_tool_materials": [ + "minecraft:cobblestone", + "minecraft:cobbled_deepslate", + "minecraft:blackstone" + ], + "minecraft:transform_materials": [ + "minecraft:netherite_ingot" + ], + "minecraft:transform_templates": [ + "minecraft:netherite_upgrade_smithing_template" + ], + "minecraft:transformable_items": [ + "minecraft:diamond_sword", + "minecraft:diamond_shovel", + "minecraft:diamond_pickaxe", + "minecraft:diamond_axe", + "minecraft:diamond_hoe", + "minecraft:diamond_helmet", + "minecraft:diamond_chestplate", + "minecraft:diamond_leggings", + "minecraft:diamond_boots", + "minecraft:golden_boots" + ], + "minecraft:trim_materials": [ + "minecraft:gold_ingot", + "minecraft:iron_ingot", + "minecraft:diamond", + "minecraft:redstone", + "minecraft:netherite_ingot", + "minecraft:lapis_lazuli", + "minecraft:quartz", + "minecraft:copper_ingot", + "minecraft:emerald", + "minecraft:amethyst_shard" + ], + "minecraft:trim_templates": [ + "minecraft:vex_armor_trim_smithing_template", + "minecraft:wild_armor_trim_smithing_template", + "minecraft:flow_armor_trim_smithing_template", + "minecraft:raiser_armor_trim_smithing_template", + "minecraft:silence_armor_trim_smithing_template", + "minecraft:coast_armor_trim_smithing_template", + "minecraft:snout_armor_trim_smithing_template", + "minecraft:dune_armor_trim_smithing_template", + "minecraft:rib_armor_trim_smithing_template", + "minecraft:host_armor_trim_smithing_template", + "minecraft:bolt_armor_trim_smithing_template", + "minecraft:shaper_armor_trim_smithing_template", + "minecraft:eye_armor_trim_smithing_template", + "minecraft:spire_armor_trim_smithing_template", + "minecraft:sentry_armor_trim_smithing_template", + "minecraft:ward_armor_trim_smithing_template", + "minecraft:tide_armor_trim_smithing_template", + "minecraft:wayfinder_armor_trim_smithing_template" + ], + "minecraft:trimmable_armors": [ + "minecraft:netherite_boots", + "minecraft:chainmail_helmet", + "minecraft:leather_helmet", + "minecraft:leather_chestplate", + "minecraft:leather_leggings", + "minecraft:leather_boots", + "minecraft:chainmail_chestplate", + "minecraft:chainmail_leggings", + "minecraft:chainmail_boots", + "minecraft:iron_helmet", + "minecraft:iron_chestplate", + "minecraft:iron_leggings", + "minecraft:iron_boots", + "minecraft:diamond_helmet", + "minecraft:diamond_chestplate", + "minecraft:diamond_leggings", + "minecraft:diamond_boots", + "minecraft:golden_helmet", + "minecraft:golden_chestplate", + "minecraft:golden_leggings", + "minecraft:golden_boots", + "minecraft:turtle_helmet", + "minecraft:netherite_chestplate", + "minecraft:netherite_leggings", + "minecraft:netherite_helmet" + ], + "minecraft:vibration_damper": [ + "minecraft:black_carpet", + "minecraft:blue_carpet", + "minecraft:pink_carpet", + "minecraft:lime_carpet", + "minecraft:green_wool", + "minecraft:cyan_carpet", + "minecraft:orange_wool", + "minecraft:white_carpet", + "minecraft:purple_carpet", + "minecraft:yellow_carpet", + "minecraft:light_gray_wool", + "minecraft:magenta_carpet", + "minecraft:purple_wool", + "minecraft:gray_wool", + "minecraft:red_carpet", + "minecraft:brown_carpet", + "minecraft:light_blue_wool", + "minecraft:white_wool", + "minecraft:magenta_wool", + "minecraft:yellow_wool", + "minecraft:lime_wool", + "minecraft:pink_wool", + "minecraft:cyan_wool", + "minecraft:blue_wool", + "minecraft:brown_wool", + "minecraft:red_wool", + "minecraft:black_wool", + "minecraft:orange_carpet", + "minecraft:light_blue_carpet", + "minecraft:gray_carpet", + "minecraft:light_gray_carpet", + "minecraft:green_carpet" + ], + "minecraft:warped_stems": [ + "minecraft:stripped_warped_hyphae", + "minecraft:stripped_warped_stem", + "minecraft:warped_hyphae", + "minecraft:warped_stem" + ], + "minecraft:wooden_slabs": [ + "minecraft:birch_slab", + "minecraft:oak_slab", + "minecraft:spruce_slab", + "minecraft:bamboo_slab", + "minecraft:warped_slab", + "minecraft:mangrove_slab", + "minecraft:cherry_slab", + "minecraft:jungle_slab", + "minecraft:acacia_slab", + "minecraft:dark_oak_slab", + "minecraft:crimson_slab" + ], + "minecraft:wooden_tier": [ + "minecraft:wooden_pickaxe", + "minecraft:wooden_shovel", + "minecraft:wooden_sword", + "minecraft:wooden_axe", + "minecraft:wooden_hoe" + ], + "minecraft:wool": [ + "minecraft:green_wool", + "minecraft:orange_wool", + "minecraft:light_gray_wool", + "minecraft:purple_wool", + "minecraft:gray_wool", + "minecraft:light_blue_wool", + "minecraft:white_wool", + "minecraft:magenta_wool", + "minecraft:yellow_wool", + "minecraft:lime_wool", + "minecraft:pink_wool", + "minecraft:cyan_wool", + "minecraft:blue_wool", + "minecraft:brown_wool", + "minecraft:red_wool", + "minecraft:black_wool" + ] +} \ No newline at end of file diff --git a/core/src/main/resources/bedrock/item_tags.1_21_40.json b/core/src/main/resources/bedrock/item_tags.1_21_40.json new file mode 100644 index 000000000..d9e63ed26 --- /dev/null +++ b/core/src/main/resources/bedrock/item_tags.1_21_40.json @@ -0,0 +1,806 @@ +{ + "minecraft:arrow": [ + "minecraft:arrow" + ], + "minecraft:banner": [ + "minecraft:banner" + ], + "minecraft:boat": [ + "minecraft:cherry_chest_boat", + "minecraft:oak_chest_boat", + "minecraft:mangrove_boat", + "minecraft:oak_boat", + "minecraft:birch_boat", + "minecraft:jungle_boat", + "minecraft:spruce_boat", + "minecraft:acacia_boat", + "minecraft:dark_oak_boat", + "minecraft:birch_chest_boat", + "minecraft:jungle_chest_boat", + "minecraft:spruce_chest_boat", + "minecraft:acacia_chest_boat", + "minecraft:dark_oak_chest_boat", + "minecraft:mangrove_chest_boat", + "minecraft:cherry_boat", + "minecraft:bamboo_raft", + "minecraft:bamboo_chest_raft" + ], + "minecraft:boats": [ + "minecraft:cherry_chest_boat", + "minecraft:oak_chest_boat", + "minecraft:mangrove_boat", + "minecraft:oak_boat", + "minecraft:birch_boat", + "minecraft:jungle_boat", + "minecraft:spruce_boat", + "minecraft:acacia_boat", + "minecraft:dark_oak_boat", + "minecraft:birch_chest_boat", + "minecraft:jungle_chest_boat", + "minecraft:spruce_chest_boat", + "minecraft:acacia_chest_boat", + "minecraft:dark_oak_chest_boat", + "minecraft:mangrove_chest_boat", + "minecraft:cherry_boat", + "minecraft:bamboo_raft", + "minecraft:bamboo_chest_raft" + ], + "minecraft:bookshelf_books": [ + "minecraft:written_book", + "minecraft:book", + "minecraft:writable_book", + "minecraft:enchanted_book" + ], + "minecraft:chainmail_tier": [ + "minecraft:chainmail_helmet", + "minecraft:chainmail_chestplate", + "minecraft:chainmail_leggings", + "minecraft:chainmail_boots" + ], + "minecraft:coals": [ + "minecraft:coal", + "minecraft:charcoal" + ], + "minecraft:crimson_stems": [ + "minecraft:stripped_crimson_stem", + "minecraft:crimson_hyphae", + "minecraft:crimson_stem", + "minecraft:stripped_crimson_hyphae" + ], + "minecraft:decorated_pot_sherds": [ + "minecraft:skull_pottery_sherd", + "minecraft:mourner_pottery_sherd", + "minecraft:angler_pottery_sherd", + "minecraft:prize_pottery_sherd", + "minecraft:arms_up_pottery_sherd", + "minecraft:burn_pottery_sherd", + "minecraft:snort_pottery_sherd", + "minecraft:brick", + "minecraft:heartbreak_pottery_sherd", + "minecraft:miner_pottery_sherd", + "minecraft:brewer_pottery_sherd", + "minecraft:plenty_pottery_sherd", + "minecraft:scrape_pottery_sherd", + "minecraft:howl_pottery_sherd", + "minecraft:explorer_pottery_sherd", + "minecraft:archer_pottery_sherd", + "minecraft:blade_pottery_sherd", + "minecraft:danger_pottery_sherd", + "minecraft:flow_pottery_sherd", + "minecraft:friend_pottery_sherd", + "minecraft:guster_pottery_sherd", + "minecraft:heart_pottery_sherd", + "minecraft:sheaf_pottery_sherd", + "minecraft:shelter_pottery_sherd" + ], + "minecraft:diamond_tier": [ + "minecraft:diamond_sword", + "minecraft:diamond_shovel", + "minecraft:diamond_pickaxe", + "minecraft:diamond_axe", + "minecraft:mace", + "minecraft:diamond_hoe", + "minecraft:diamond_helmet", + "minecraft:diamond_chestplate", + "minecraft:diamond_leggings", + "minecraft:diamond_boots" + ], + "minecraft:digger": [ + "minecraft:iron_shovel", + "minecraft:wooden_pickaxe", + "minecraft:iron_pickaxe", + "minecraft:iron_axe", + "minecraft:wooden_shovel", + "minecraft:wooden_axe", + "minecraft:stone_shovel", + "minecraft:stone_pickaxe", + "minecraft:stone_axe", + "minecraft:diamond_shovel", + "minecraft:diamond_pickaxe", + "minecraft:diamond_axe", + "minecraft:golden_shovel", + "minecraft:golden_pickaxe", + "minecraft:golden_axe", + "minecraft:wooden_hoe", + "minecraft:stone_hoe", + "minecraft:iron_hoe", + "minecraft:diamond_hoe", + "minecraft:golden_hoe", + "minecraft:netherite_pickaxe", + "minecraft:netherite_shovel", + "minecraft:netherite_axe", + "minecraft:netherite_hoe" + ], + "minecraft:door": [ + "minecraft:weathered_copper_door", + "minecraft:warped_door", + "minecraft:wooden_door", + "minecraft:jungle_door", + "minecraft:waxed_weathered_copper_door", + "minecraft:iron_door", + "minecraft:mangrove_door", + "minecraft:exposed_copper_door", + "minecraft:bamboo_door", + "minecraft:spruce_door", + "minecraft:birch_door", + "minecraft:acacia_door", + "minecraft:dark_oak_door", + "minecraft:crimson_door", + "minecraft:cherry_door", + "minecraft:copper_door", + "minecraft:oxidized_copper_door", + "minecraft:waxed_copper_door", + "minecraft:waxed_exposed_copper_door", + "minecraft:waxed_oxidized_copper_door" + ], + "minecraft:golden_tier": [ + "minecraft:golden_sword", + "minecraft:golden_shovel", + "minecraft:golden_pickaxe", + "minecraft:golden_axe", + "minecraft:golden_hoe", + "minecraft:golden_helmet", + "minecraft:golden_chestplate", + "minecraft:golden_leggings", + "minecraft:golden_boots" + ], + "minecraft:hanging_actor": [ + "minecraft:painting" + ], + "minecraft:hanging_sign": [ + "minecraft:mangrove_hanging_sign", + "minecraft:bamboo_hanging_sign", + "minecraft:spruce_hanging_sign", + "minecraft:birch_hanging_sign", + "minecraft:cherry_hanging_sign", + "minecraft:oak_hanging_sign", + "minecraft:jungle_hanging_sign", + "minecraft:acacia_hanging_sign", + "minecraft:dark_oak_hanging_sign", + "minecraft:crimson_hanging_sign", + "minecraft:warped_hanging_sign" + ], + "minecraft:horse_armor": [ + "minecraft:iron_horse_armor", + "minecraft:golden_horse_armor", + "minecraft:leather_horse_armor", + "minecraft:diamond_horse_armor" + ], + "minecraft:iron_tier": [ + "minecraft:iron_chestplate", + "minecraft:iron_shovel", + "minecraft:iron_sword", + "minecraft:iron_pickaxe", + "minecraft:iron_axe", + "minecraft:iron_hoe", + "minecraft:iron_helmet", + "minecraft:iron_leggings", + "minecraft:iron_boots" + ], + "minecraft:is_armor": [ + "minecraft:iron_chestplate", + "minecraft:netherite_boots", + "minecraft:chainmail_helmet", + "minecraft:elytra", + "minecraft:leather_helmet", + "minecraft:leather_chestplate", + "minecraft:leather_leggings", + "minecraft:leather_boots", + "minecraft:chainmail_chestplate", + "minecraft:chainmail_leggings", + "minecraft:chainmail_boots", + "minecraft:iron_helmet", + "minecraft:iron_leggings", + "minecraft:iron_boots", + "minecraft:diamond_helmet", + "minecraft:diamond_chestplate", + "minecraft:diamond_leggings", + "minecraft:diamond_boots", + "minecraft:golden_helmet", + "minecraft:golden_chestplate", + "minecraft:golden_leggings", + "minecraft:golden_boots", + "minecraft:turtle_helmet", + "minecraft:netherite_chestplate", + "minecraft:netherite_leggings", + "minecraft:netherite_helmet" + ], + "minecraft:is_axe": [ + "minecraft:iron_axe", + "minecraft:wooden_axe", + "minecraft:stone_axe", + "minecraft:diamond_axe", + "minecraft:golden_axe", + "minecraft:netherite_axe" + ], + "minecraft:is_cooked": [ + "minecraft:cooked_cod", + "minecraft:cooked_porkchop", + "minecraft:cooked_salmon", + "minecraft:cooked_rabbit", + "minecraft:cooked_beef", + "minecraft:cooked_chicken", + "minecraft:rabbit_stew", + "minecraft:cooked_mutton" + ], + "minecraft:is_fish": [ + "minecraft:cooked_cod", + "minecraft:cooked_salmon", + "minecraft:cod", + "minecraft:salmon", + "minecraft:tropical_fish", + "minecraft:pufferfish" + ], + "minecraft:is_food": [ + "minecraft:rabbit", + "minecraft:cooked_porkchop", + "minecraft:mushroom_stew", + "minecraft:potato", + "minecraft:enchanted_golden_apple", + "minecraft:golden_carrot", + "minecraft:carrot", + "minecraft:chicken", + "minecraft:beetroot", + "minecraft:sweet_berries", + "minecraft:apple", + "minecraft:golden_apple", + "minecraft:bread", + "minecraft:porkchop", + "minecraft:cookie", + "minecraft:cooked_rabbit", + "minecraft:beef", + "minecraft:dried_kelp", + "minecraft:beetroot_soup", + "minecraft:melon_slice", + "minecraft:cooked_beef", + "minecraft:rotten_flesh", + "minecraft:cooked_chicken", + "minecraft:baked_potato", + "minecraft:pumpkin_pie", + "minecraft:rabbit_stew", + "minecraft:cooked_mutton", + "minecraft:mutton" + ], + "minecraft:is_hoe": [ + "minecraft:wooden_hoe", + "minecraft:stone_hoe", + "minecraft:iron_hoe", + "minecraft:diamond_hoe", + "minecraft:golden_hoe", + "minecraft:netherite_hoe" + ], + "minecraft:is_meat": [ + "minecraft:rabbit", + "minecraft:cooked_porkchop", + "minecraft:chicken", + "minecraft:porkchop", + "minecraft:cooked_rabbit", + "minecraft:beef", + "minecraft:cooked_beef", + "minecraft:rotten_flesh", + "minecraft:cooked_chicken", + "minecraft:rabbit_stew", + "minecraft:cooked_mutton", + "minecraft:mutton" + ], + "minecraft:is_minecart": [ + "minecraft:command_block_minecart", + "minecraft:minecart", + "minecraft:chest_minecart", + "minecraft:tnt_minecart", + "minecraft:hopper_minecart" + ], + "minecraft:is_pickaxe": [ + "minecraft:wooden_pickaxe", + "minecraft:iron_pickaxe", + "minecraft:stone_pickaxe", + "minecraft:diamond_pickaxe", + "minecraft:golden_pickaxe", + "minecraft:netherite_pickaxe" + ], + "minecraft:is_shovel": [ + "minecraft:iron_shovel", + "minecraft:wooden_shovel", + "minecraft:stone_shovel", + "minecraft:diamond_shovel", + "minecraft:golden_shovel", + "minecraft:netherite_shovel" + ], + "minecraft:is_sword": [ + "minecraft:netherite_sword", + "minecraft:iron_sword", + "minecraft:wooden_sword", + "minecraft:stone_sword", + "minecraft:diamond_sword", + "minecraft:mace", + "minecraft:golden_sword" + ], + "minecraft:is_tool": [ + "minecraft:netherite_sword", + "minecraft:iron_shovel", + "minecraft:iron_sword", + "minecraft:wooden_pickaxe", + "minecraft:iron_pickaxe", + "minecraft:iron_axe", + "minecraft:wooden_sword", + "minecraft:wooden_shovel", + "minecraft:wooden_axe", + "minecraft:stone_sword", + "minecraft:stone_shovel", + "minecraft:stone_pickaxe", + "minecraft:stone_axe", + "minecraft:diamond_sword", + "minecraft:diamond_shovel", + "minecraft:diamond_pickaxe", + "minecraft:diamond_axe", + "minecraft:mace", + "minecraft:golden_sword", + "minecraft:golden_shovel", + "minecraft:golden_pickaxe", + "minecraft:golden_axe", + "minecraft:wooden_hoe", + "minecraft:stone_hoe", + "minecraft:iron_hoe", + "minecraft:diamond_hoe", + "minecraft:golden_hoe", + "minecraft:netherite_pickaxe", + "minecraft:netherite_shovel", + "minecraft:netherite_axe", + "minecraft:netherite_hoe" + ], + "minecraft:is_trident": [ + "minecraft:trident" + ], + "minecraft:leather_tier": [ + "minecraft:leather_helmet", + "minecraft:leather_chestplate", + "minecraft:leather_leggings", + "minecraft:leather_boots" + ], + "minecraft:lectern_books": [ + "minecraft:written_book", + "minecraft:writable_book" + ], + "minecraft:logs": [ + "minecraft:mangrove_wood", + "minecraft:spruce_wood", + "minecraft:stripped_cherry_wood", + "minecraft:stripped_crimson_stem", + "minecraft:stripped_spruce_wood", + "minecraft:spruce_log", + "minecraft:acacia_wood", + "minecraft:stripped_acacia_wood", + "minecraft:stripped_warped_hyphae", + "minecraft:acacia_log", + "minecraft:stripped_warped_stem", + "minecraft:oak_log", + "minecraft:birch_log", + "minecraft:jungle_log", + "minecraft:dark_oak_log", + "minecraft:jungle_wood", + "minecraft:stripped_jungle_wood", + "minecraft:oak_wood", + "minecraft:birch_wood", + "minecraft:dark_oak_wood", + "minecraft:stripped_oak_wood", + "minecraft:stripped_birch_wood", + "minecraft:stripped_dark_oak_wood", + "minecraft:stripped_oak_log", + "minecraft:stripped_dark_oak_log", + "minecraft:mangrove_log", + "minecraft:stripped_jungle_log", + "minecraft:stripped_mangrove_wood", + "minecraft:crimson_hyphae", + "minecraft:stripped_cherry_log", + "minecraft:stripped_birch_log", + "minecraft:stripped_acacia_log", + "minecraft:crimson_stem", + "minecraft:warped_hyphae", + "minecraft:stripped_spruce_log", + "minecraft:warped_stem", + "minecraft:stripped_crimson_hyphae", + "minecraft:cherry_wood", + "minecraft:cherry_log", + "minecraft:stripped_mangrove_log" + ], + "minecraft:logs_that_burn": [ + "minecraft:mangrove_wood", + "minecraft:spruce_wood", + "minecraft:stripped_cherry_wood", + "minecraft:stripped_spruce_wood", + "minecraft:spruce_log", + "minecraft:acacia_wood", + "minecraft:stripped_acacia_wood", + "minecraft:acacia_log", + "minecraft:oak_log", + "minecraft:birch_log", + "minecraft:jungle_log", + "minecraft:dark_oak_log", + "minecraft:jungle_wood", + "minecraft:stripped_jungle_wood", + "minecraft:oak_wood", + "minecraft:birch_wood", + "minecraft:dark_oak_wood", + "minecraft:stripped_oak_wood", + "minecraft:stripped_birch_wood", + "minecraft:stripped_dark_oak_wood", + "minecraft:stripped_oak_log", + "minecraft:stripped_dark_oak_log", + "minecraft:mangrove_log", + "minecraft:stripped_jungle_log", + "minecraft:stripped_mangrove_wood", + "minecraft:stripped_cherry_log", + "minecraft:stripped_birch_log", + "minecraft:stripped_acacia_log", + "minecraft:stripped_spruce_log", + "minecraft:cherry_wood", + "minecraft:cherry_log", + "minecraft:stripped_mangrove_log" + ], + "minecraft:mangrove_logs": [ + "minecraft:mangrove_wood", + "minecraft:mangrove_log", + "minecraft:stripped_mangrove_wood", + "minecraft:stripped_mangrove_log" + ], + "minecraft:music_disc": [ + "minecraft:music_disc_ward", + "minecraft:music_disc_stal", + "minecraft:music_disc_wait", + "minecraft:music_disc_cat", + "minecraft:music_disc_strad", + "minecraft:music_disc_chirp", + "minecraft:music_disc_mall", + "minecraft:music_disc_creator_music_box", + "minecraft:music_disc_pigstep", + "minecraft:music_disc_11", + "minecraft:music_disc_13", + "minecraft:music_disc_blocks", + "minecraft:music_disc_far", + "minecraft:music_disc_mellohi", + "minecraft:music_disc_otherside", + "minecraft:music_disc_5", + "minecraft:music_disc_relic", + "minecraft:music_disc_creator", + "minecraft:music_disc_precipice" + ], + "minecraft:netherite_tier": [ + "minecraft:netherite_sword", + "minecraft:netherite_boots", + "minecraft:netherite_chestplate", + "minecraft:netherite_pickaxe", + "minecraft:netherite_leggings", + "minecraft:netherite_shovel", + "minecraft:netherite_axe", + "minecraft:netherite_hoe", + "minecraft:netherite_helmet" + ], + "minecraft:planks": [ + "minecraft:spruce_planks", + "minecraft:oak_planks", + "minecraft:mangrove_planks", + "minecraft:dark_oak_planks", + "minecraft:birch_planks", + "minecraft:jungle_planks", + "minecraft:acacia_planks", + "minecraft:bamboo_planks", + "minecraft:warped_planks", + "minecraft:crimson_planks", + "minecraft:cherry_planks" + ], + "minecraft:sand": [ + "minecraft:sand", + "minecraft:red_sand" + ], + "minecraft:sign": [ + "minecraft:jungle_sign", + "minecraft:bamboo_sign", + "minecraft:mangrove_hanging_sign", + "minecraft:cherry_sign", + "minecraft:oak_sign", + "minecraft:bamboo_hanging_sign", + "minecraft:warped_sign", + "minecraft:spruce_sign", + "minecraft:spruce_hanging_sign", + "minecraft:acacia_sign", + "minecraft:birch_hanging_sign", + "minecraft:birch_sign", + "minecraft:dark_oak_sign", + "minecraft:mangrove_sign", + "minecraft:crimson_sign", + "minecraft:cherry_hanging_sign", + "minecraft:oak_hanging_sign", + "minecraft:jungle_hanging_sign", + "minecraft:acacia_hanging_sign", + "minecraft:dark_oak_hanging_sign", + "minecraft:crimson_hanging_sign", + "minecraft:warped_hanging_sign" + ], + "minecraft:soul_fire_base_blocks": [ + "minecraft:soul_soil", + "minecraft:soul_sand" + ], + "minecraft:spawn_egg": [ + "minecraft:enderman_spawn_egg", + "minecraft:endermite_spawn_egg", + "minecraft:tropical_fish_spawn_egg", + "minecraft:ravager_spawn_egg", + "minecraft:pufferfish_spawn_egg", + "minecraft:zoglin_spawn_egg", + "minecraft:strider_spawn_egg", + "minecraft:slime_spawn_egg", + "minecraft:glow_squid_spawn_egg", + "minecraft:blaze_spawn_egg", + "minecraft:witch_spawn_egg", + "minecraft:horse_spawn_egg", + "minecraft:polar_bear_spawn_egg", + "minecraft:pillager_spawn_egg", + "minecraft:stray_spawn_egg", + "minecraft:zombie_pigman_spawn_egg", + "minecraft:snow_golem_spawn_egg", + "minecraft:panda_spawn_egg", + "minecraft:axolotl_spawn_egg", + "minecraft:agent_spawn_egg", + "minecraft:shulker_spawn_egg", + "minecraft:vindicator_spawn_egg", + "minecraft:evoker_spawn_egg", + "minecraft:parrot_spawn_egg", + "minecraft:wolf_spawn_egg", + "minecraft:sheep_spawn_egg", + "minecraft:elder_guardian_spawn_egg", + "minecraft:silverfish_spawn_egg", + "minecraft:tadpole_spawn_egg", + "minecraft:cow_spawn_egg", + "minecraft:bogged_spawn_egg", + "minecraft:ocelot_spawn_egg", + "minecraft:bee_spawn_egg", + "minecraft:piglin_brute_spawn_egg", + "minecraft:rabbit_spawn_egg", + "minecraft:camel_spawn_egg", + "minecraft:creeper_spawn_egg", + "minecraft:drowned_spawn_egg", + "minecraft:chicken_spawn_egg", + "minecraft:pig_spawn_egg", + "minecraft:mooshroom_spawn_egg", + "minecraft:skeleton_spawn_egg", + "minecraft:spider_spawn_egg", + "minecraft:zombie_spawn_egg", + "minecraft:villager_spawn_egg", + "minecraft:squid_spawn_egg", + "minecraft:bat_spawn_egg", + "minecraft:ghast_spawn_egg", + "minecraft:magma_cube_spawn_egg", + "minecraft:cave_spider_spawn_egg", + "minecraft:guardian_spawn_egg", + "minecraft:husk_spawn_egg", + "minecraft:piglin_spawn_egg", + "minecraft:wither_skeleton_spawn_egg", + "minecraft:donkey_spawn_egg", + "minecraft:mule_spawn_egg", + "minecraft:skeleton_horse_spawn_egg", + "minecraft:zombie_horse_spawn_egg", + "minecraft:npc_spawn_egg", + "minecraft:breeze_spawn_egg", + "minecraft:llama_spawn_egg", + "minecraft:vex_spawn_egg", + "minecraft:warden_spawn_egg", + "minecraft:zombie_villager_spawn_egg", + "minecraft:cod_spawn_egg", + "minecraft:salmon_spawn_egg", + "minecraft:dolphin_spawn_egg", + "minecraft:turtle_spawn_egg", + "minecraft:phantom_spawn_egg", + "minecraft:cat_spawn_egg", + "minecraft:fox_spawn_egg", + "minecraft:wandering_trader_spawn_egg", + "minecraft:hoglin_spawn_egg", + "minecraft:sniffer_spawn_egg", + "minecraft:goat_spawn_egg", + "minecraft:iron_golem_spawn_egg", + "minecraft:ender_dragon_spawn_egg", + "minecraft:wither_spawn_egg", + "minecraft:frog_spawn_egg", + "minecraft:allay_spawn_egg", + "minecraft:trader_llama_spawn_egg", + "minecraft:armadillo_spawn_egg", + "minecraft:spawn_egg" + ], + "minecraft:stone_bricks": [ + "minecraft:mossy_stone_bricks", + "minecraft:stone_bricks", + "minecraft:cracked_stone_bricks", + "minecraft:chiseled_stone_bricks" + ], + "minecraft:stone_crafting_materials": [ + "minecraft:cobblestone", + "minecraft:cobbled_deepslate", + "minecraft:blackstone" + ], + "minecraft:stone_tier": [ + "minecraft:stone_sword", + "minecraft:stone_shovel", + "minecraft:stone_pickaxe", + "minecraft:stone_axe", + "minecraft:stone_hoe" + ], + "minecraft:stone_tool_materials": [ + "minecraft:cobblestone", + "minecraft:cobbled_deepslate", + "minecraft:blackstone" + ], + "minecraft:transform_materials": [ + "minecraft:netherite_ingot" + ], + "minecraft:transform_templates": [ + "minecraft:netherite_upgrade_smithing_template" + ], + "minecraft:transformable_items": [ + "minecraft:diamond_sword", + "minecraft:diamond_shovel", + "minecraft:diamond_pickaxe", + "minecraft:diamond_axe", + "minecraft:diamond_hoe", + "minecraft:diamond_helmet", + "minecraft:diamond_chestplate", + "minecraft:diamond_leggings", + "minecraft:diamond_boots", + "minecraft:golden_boots" + ], + "minecraft:trim_materials": [ + "minecraft:diamond", + "minecraft:iron_ingot", + "minecraft:gold_ingot", + "minecraft:redstone", + "minecraft:netherite_ingot", + "minecraft:lapis_lazuli", + "minecraft:quartz", + "minecraft:copper_ingot", + "minecraft:emerald", + "minecraft:amethyst_shard" + ], + "minecraft:trim_templates": [ + "minecraft:coast_armor_trim_smithing_template", + "minecraft:vex_armor_trim_smithing_template", + "minecraft:wild_armor_trim_smithing_template", + "minecraft:flow_armor_trim_smithing_template", + "minecraft:silence_armor_trim_smithing_template", + "minecraft:snout_armor_trim_smithing_template", + "minecraft:dune_armor_trim_smithing_template", + "minecraft:rib_armor_trim_smithing_template", + "minecraft:host_armor_trim_smithing_template", + "minecraft:eye_armor_trim_smithing_template", + "minecraft:spire_armor_trim_smithing_template", + "minecraft:sentry_armor_trim_smithing_template", + "minecraft:ward_armor_trim_smithing_template", + "minecraft:tide_armor_trim_smithing_template", + "minecraft:wayfinder_armor_trim_smithing_template", + "minecraft:raiser_armor_trim_smithing_template", + "minecraft:shaper_armor_trim_smithing_template", + "minecraft:bolt_armor_trim_smithing_template" + ], + "minecraft:trimmable_armors": [ + "minecraft:iron_chestplate", + "minecraft:netherite_boots", + "minecraft:chainmail_helmet", + "minecraft:leather_helmet", + "minecraft:leather_chestplate", + "minecraft:leather_leggings", + "minecraft:leather_boots", + "minecraft:chainmail_chestplate", + "minecraft:chainmail_leggings", + "minecraft:chainmail_boots", + "minecraft:iron_helmet", + "minecraft:iron_leggings", + "minecraft:iron_boots", + "minecraft:diamond_helmet", + "minecraft:diamond_chestplate", + "minecraft:diamond_leggings", + "minecraft:diamond_boots", + "minecraft:golden_helmet", + "minecraft:golden_chestplate", + "minecraft:golden_leggings", + "minecraft:golden_boots", + "minecraft:turtle_helmet", + "minecraft:netherite_chestplate", + "minecraft:netherite_leggings", + "minecraft:netherite_helmet" + ], + "minecraft:vibration_damper": [ + "minecraft:black_carpet", + "minecraft:pink_carpet", + "minecraft:lime_carpet", + "minecraft:blue_carpet", + "minecraft:green_wool", + "minecraft:cyan_carpet", + "minecraft:orange_wool", + "minecraft:white_carpet", + "minecraft:purple_carpet", + "minecraft:yellow_carpet", + "minecraft:light_gray_wool", + "minecraft:magenta_carpet", + "minecraft:purple_wool", + "minecraft:gray_wool", + "minecraft:red_carpet", + "minecraft:brown_carpet", + "minecraft:light_blue_wool", + "minecraft:white_wool", + "minecraft:magenta_wool", + "minecraft:yellow_wool", + "minecraft:lime_wool", + "minecraft:pink_wool", + "minecraft:cyan_wool", + "minecraft:blue_wool", + "minecraft:brown_wool", + "minecraft:red_wool", + "minecraft:black_wool", + "minecraft:orange_carpet", + "minecraft:light_blue_carpet", + "minecraft:gray_carpet", + "minecraft:light_gray_carpet", + "minecraft:green_carpet" + ], + "minecraft:warped_stems": [ + "minecraft:stripped_warped_hyphae", + "minecraft:stripped_warped_stem", + "minecraft:warped_hyphae", + "minecraft:warped_stem" + ], + "minecraft:wooden_slabs": [ + "minecraft:birch_slab", + "minecraft:oak_slab", + "minecraft:spruce_slab", + "minecraft:bamboo_slab", + "minecraft:warped_slab", + "minecraft:mangrove_slab", + "minecraft:cherry_slab", + "minecraft:jungle_slab", + "minecraft:acacia_slab", + "minecraft:dark_oak_slab", + "minecraft:crimson_slab" + ], + "minecraft:wooden_tier": [ + "minecraft:wooden_pickaxe", + "minecraft:wooden_sword", + "minecraft:wooden_shovel", + "minecraft:wooden_axe", + "minecraft:wooden_hoe" + ], + "minecraft:wool": [ + "minecraft:green_wool", + "minecraft:orange_wool", + "minecraft:light_gray_wool", + "minecraft:purple_wool", + "minecraft:gray_wool", + "minecraft:light_blue_wool", + "minecraft:white_wool", + "minecraft:magenta_wool", + "minecraft:yellow_wool", + "minecraft:lime_wool", + "minecraft:pink_wool", + "minecraft:cyan_wool", + "minecraft:blue_wool", + "minecraft:brown_wool", + "minecraft:red_wool", + "minecraft:black_wool" + ] +} diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index a6d04157d..e1eafe2c5 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit a6d04157d1866e55e35f2ce3ebde3cf4e007aabf +Subproject commit e1eafe2c5304012d23acba80659459f7868fe2b1 diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/ScoreboardIssueTests.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/ScoreboardIssueTests.java index 17ad7f3d3..7ab518f1d 100644 --- a/core/src/test/java/org/geysermc/geyser/scoreboard/network/ScoreboardIssueTests.java +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/ScoreboardIssueTests.java @@ -25,14 +25,6 @@ package org.geysermc.geyser.scoreboard.network; -import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNextPacket; -import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNextPacketMatch; -import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNextPacketType; -import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNoNextPacket; -import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.mockContextScoreboard; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.junit.jupiter.api.Assertions.assertEquals; - import net.kyori.adventure.text.Component; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; @@ -75,6 +67,11 @@ import java.util.EnumSet; import java.util.Optional; import java.util.UUID; +import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.*; +import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.mockContextScoreboard; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; + /** * Tests for issues reported on GitHub. */ @@ -157,7 +154,7 @@ public class ScoreboardIssueTests { new ClientboundPlayerInfoUpdatePacket( EnumSet.of(PlayerListEntryAction.ADD_PLAYER, PlayerListEntryAction.UPDATE_LISTED), new PlayerListEntry[] { - new PlayerListEntry(npcUuid, new GameProfile(npcUuid, "1297"), false, 0, GameMode.SURVIVAL, null, null, 0, null, null) + new PlayerListEntry(npcUuid, new GameProfile(npcUuid, "1297"), false, 0, GameMode.SURVIVAL, null, 0, null, 0, null, null) })); //todo we don't have to remove an entry that was never in the playerlist in the first place diff --git a/gradle.properties b/gradle.properties index 86cf4e922..09943725b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,10 @@ org.gradle.parallel=true org.gradle.caching=true org.gradle.vfs.watch=false +# TODO remove once architectury loom updates to 1.8 +loom.ignoreDependencyLoomVersionValidation=true + group=org.geysermc id=geyser -version=2.4.4-SNAPSHOT +version=2.5.0-SNAPSHOT description=Allows for players from Minecraft: Bedrock Edition to join Minecraft: Java Edition servers. diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e50809b52..b8908f518 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ protocol-common = "3.0.0.Beta5-20241022.154658-14" protocol-codec = "3.0.0.Beta5-20241022.154658-14" raknet = "1.0.0.CR3-20240416.144209-1" minecraftauth = "4.1.1" -mcprotocollib = "1.21-20241010.155958-24" +mcprotocollib = "1.21.2-20241103.011758-1" adventure = "4.14.0" adventure-platform = "4.3.0" junit = "5.9.2" @@ -25,7 +25,7 @@ jline = "3.21.0" terminalconsoleappender = "1.2.0" folia = "1.19.4-R0.1-SNAPSHOT" viaversion = "4.9.2" -adapters = "1.13-SNAPSHOT" +adapters = "1.14-SNAPSHOT" cloud = "2.0.0-rc.2" cloud-minecraft = "2.0.0-beta.9" cloud-minecraft-modded = "2.0.0-beta.7" @@ -33,12 +33,12 @@ commodore = "2.2" bungeecord = "a7c6ede" velocity = "3.3.0-SNAPSHOT" viaproxy = "3.3.2-SNAPSHOT" -fabric-loader = "0.15.11" -fabric-api = "0.100.1+1.21" -neoforge-minecraft = "21.1.1" +fabric-loader = "0.16.7" +fabric-api = "0.106.1+1.21.3" +neoforge-minecraft = "21.3.0-beta" mixin = "0.8.5" mixinextras = "0.3.5" -minecraft = "1.21.1" +minecraft = "1.21.3" mockito = "5.+" # plugin versions @@ -60,7 +60,8 @@ erosion-bukkit-nms = { group = "org.geysermc.erosion", name = "bukkit-nms", vers erosion-common = { group = "org.geysermc.erosion", name = "common", version.ref = "erosion" } jackson-annotations = { group = "com.fasterxml.jackson.core", name = "jackson-annotations", version.ref = "jackson" } -jackson-core = { group = "com.fasterxml.jackson.core", name = "jackson-databind", version.ref = "jackson" } +jackson-databind = { group = "com.fasterxml.jackson.core", name = "jackson-databind", version.ref = "jackson" } +jackson-core = { group = "com.fasterxml.jackson.core", name = "jackson-core", version.ref = "jackson" } jackson-dataformat-yaml = { group = "com.fasterxml.jackson.dataformat", name = "jackson-dataformat-yaml", version.ref = "jackson" } fastutil-int-int-maps = { group = "com.nukkitx.fastutil", name = "fastutil-int-int-maps", version.ref = "fastutil" } @@ -105,7 +106,7 @@ mixinextras = { module = "io.github.llamalad7:mixinextras-common", version.ref = minecraft = { group = "com.mojang", name = "minecraft", version.ref = "minecraft" } -# Check these on https://modmuss50.me/fabric.html +# Check these on https://fabricmc.net/develop/ fabric-loader = { group = "net.fabricmc", name = "fabric-loader", version.ref = "fabric-loader" } fabric-api = { group = "net.fabricmc.fabric-api", name = "fabric-api", version.ref = "fabric-api" } @@ -149,7 +150,7 @@ indra = { id = "net.kyori.indra", version.ref = "indra" } blossom = { id = "net.kyori.blossom", version.ref = "blossom" } [bundles] -jackson = [ "jackson-annotations", "jackson-core", "jackson-dataformat-yaml" ] +jackson = [ "jackson-annotations", "jackson-databind", "jackson-dataformat-yaml" ] fastutil = [ "fastutil-int-int-maps", "fastutil-int-long-maps", "fastutil-int-byte-maps", "fastutil-int-boolean-maps", "fastutil-object-int-maps", "fastutil-object-object-maps" ] adventure = [ "adventure-text-serializer-gson", "adventure-text-serializer-legacy", "adventure-text-serializer-plain" ] log4j = [ "log4j-api", "log4j-core", "log4j-slf4j2-impl" ]